[CF1192B]动态直径

题意

给一棵固定形态的树,边有边权,每次修改一条边权,在线求出修改后树的直径。


思考

写出树的全dfs序。生成方式为:每当一个点进栈或入栈时,记录它的编号。

考虑这个dfs序上两点之间的距离。设某个节点在dfs序中第一次出现的位置为$where_i$,第i个位置的节点为$what_i$两个点分别为u和v。可以发现,在dfs上,u和v之间一堆灰包含它们的lca,则:

$$dis_{u,v}=min_{where_u \leq x \leq where_v}{\{dep_u+dep_v-2*dep_{what_x}\}}$$

树的直径即为上述表达式的最大值。

考虑到直径的形式为u-lca-v的形式,我们可以在dfs序上看成是L、M、R的这三部分组成,其中L和R要尽可能大,M要尽可能小(代码中先加了符号,所以还是最大的)。考虑线段树,维护当前区间的最大值、M、LM、MR和LMR,最后的答案即为线段树根节点的LMR。不难证明,可以进行如下合并:
$val=max{\{val_l,val_r\}}$

$M=max{\{M_l,M_r\}}$(取了负号)
$LM=max{\{LM_l,LM_r,val_l+M_r\}}$
$RM=max{\{RM_l,RM_r,M_l+val_r\}}$

$LMR=max{\{LMR_l,LMR_r,LM_l+val_r,val_l+RM_r\}}$

对于修改操作,相当于是区间修改,直接打标记即可。

时间复杂度:$O(n+qlogn)$


代码

  1 // luogu-judger-enable-o2
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 const int maxn=1E5+5;
  5 typedef long long int ll;
  6 int n,m;
  7 int size=1,head[maxn*2];
  8 int dfn,dfnFirst[maxn],dfnLast[maxn],what[maxn*2],fa[maxn];
  9 ll lastans,weight[maxn],dep[maxn];
 10 ll val[maxn*8],M[maxn*8],LM[maxn*8],MR[maxn*8],LMR[maxn*8],tag[maxn*8];
 11 struct edge
 12 {
 13     int to,next;
 14     ll w;
 15 }E[maxn*2];
 16 inline void addE(int u,int v,ll w)
 17 {
 18     E[++size].to=v;
 19     E[size].next=head[u];
 20     E[size].w=w;
 21     head[u]=size;
 22 }
 23 void dfs(int u,int F,ll d)
 24 {
 25     what[dfnFirst[u]=++dfn]=u;
 26     dep[u]=d;
 27     fa[u]=F;
 28     for(int i=head[u];i;i=E[i].next)
 29     {
 30         int v=E[i].to;
 31         if(v==F)
 32             continue;
 33         weight[v]=E[i].w;
 34         dfs(v,u,d+E[i].w);
 35         what[++dfn]=u;
 36     }
 37     dfnLast[u]=dfn;
 38 }
 39 inline void pushdown(int l,int r,int num)
 40 {
 41     val[num]+=tag[num];
 42     M[num]-=tag[num]*2;
 43     LM[num]-=tag[num];
 44     MR[num]-=tag[num];
 45     if(l!=r)
 46         tag[num<<1]+=tag[num],tag[num<<1|1]+=tag[num];
 47     tag[num]=0;
 48 }
 49 inline void update(int l,int r,int num)
 50 {
 51     if(l==r)
 52         return;
 53     val[num]=max(val[num<<1],val[num<<1|1]);
 54     M[num]=max(M[num<<1],M[num<<1|1]);
 55     LM[num]=max(max(LM[num<<1],LM[num<<1|1]),val[num<<1]+M[num<<1|1]);
 56     MR[num]=max(max(MR[num<<1],MR[num<<1|1]),M[num<<1]+val[num<<1|1]);
 57     LMR[num]=max(max(LMR[num<<1],LMR[num<<1|1]),max(LM[num<<1]+val[num<<1|1],val[num<<1]+MR[num<<1|1]));
 58 }
 59 void build(int l,int r,int num)
 60 {
 61     if(l==r)
 62     {
 63         int pos=what[l];
 64         val[num]=dep[pos];
 65         M[num]=-2*dep[pos];
 66         LM[num]=MR[num]=-dep[pos];
 67         return;
 68     }
 69     int mid=(l+r)>>1;
 70     build(l,mid,num<<1),build(mid+1,r,num<<1|1);
 71     update(l,r,num);
 72 }
 73 void add(int L,int R,int l,int r,ll x,int num)
 74 {
 75     if(L<=l&&r<=R)
 76     {
 77         tag[num]+=x;
 78         pushdown(l,r,num);
 79         return;
 80     }
 81     pushdown(l,r,num);
 82     int mid=(l+r)>>1;
 83     if(R<=mid)
 84         add(L,R,l,mid,x,num<<1);
 85     else if(mid<L)
 86         add(L,R,mid+1,r,x,num<<1|1);
 87     else
 88         add(L,R,l,mid,x,num<<1),add(L,R,mid+1,r,x,num<<1|1);
 89     pushdown(l,mid,num<<1);
 90     pushdown(mid+1,r,num<<1|1);
 91     update(l,r,num);
 92 }
 93 int main()
 94 {
 95     ios::sync_with_stdio(false);
 96     ll W;
 97     cin>>n>>m>>W;
 98     for(int i=2;i<=n;++i)
 99     {
100         int x,y;
101         ll z;
102         cin>>x>>y>>z;
103         addE(x,y,z);
104         addE(y,x,z);
105     }
106     dfs(1,1,0);
107     build(1,2*n-1,1);
108     while(m--)
109     {
110         ll x,y;
111         cin>>x>>y;
112         x=(x+lastans)%(n-1)+1;
113         y=(y+lastans)%W;
114         if(fa[E[x<<1].to]==E[x<<1|1].to)
115             x=E[x<<1].to;
116         else
117             x=E[x<<1|1].to;
118         add(dfnFirst[x],dfnLast[x],1,2*n-1,y-weight[x],1);
119         weight[x]=y;
120         lastans=LMR[1];
121         cout<<lastans<<endl;
122     }
123     return 0;
124 }
View Code

猜你喜欢

转载自www.cnblogs.com/GreenDuck/p/11409292.html
今日推荐