题意
给一棵固定形态的树,边有边权,每次修改一条边权,在线求出修改后树的直径。
思考
写出树的全dfs序。生成方式为:每当一个点进栈或入栈时,记录它的编号。
考虑这个dfs序上两点之间的距离。设某个节点在dfs序中第一次出现的位置为$where_i$,第i个位置的节点为$what_i$两个点分别为u和v。可以发现,在dfs上,u和v之间一堆会包含它们的lca,则:
$$dis_{u,v}=max_{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}}$
$MR=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 }