P6845
考虑按 DFS 序建线段树,每个节点维护区间直径。
那么如果修改的边是 \((x,y)\),其中 \(x\) 是 \(y\) 的父亲,设 \(y\) 子树内 DFS 序最小值和最大值分别为 \(l,r\),那么影响到的线段树节点就是所有和 \([l,r]\) 有交且不被 \([l,r]\) 包含的区间。
由线段树的性质可知这样的区间只有 \(O(\log n)\) 个,暴力重新计算这些区间的信息即可。
由于 pushup 的时候需要查询链上和,所以复杂度是 \(O(n\log^2n)\)。有点不爽的
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
return x*f;
}
const int MN=1e5+5;
int n,q,w;
int fr[MN],to[MN],val[MN];
struct BIT{
int c[MN];
int lowbit(int x){return x&(-x);}
void add(int x,int k){for(int i=x;i<=n;i+=lowbit(i))c[i]+=k;}
int sum(int x){int res=0;for(int i=x;i;i-=lowbit(i))res+=c[i];return res;}
}T;
struct Edge{
int to,cost;
Edge(int T,int C):to(T),cost(C){}
Edge(){}
};
vector<Edge>G[MN];
namespace HLD{
int dep[MN],dfn[MN],sz[MN],hson[MN],top[MN],fa[MN];
int dis[MN],rk[MN];
void dfs1(int u,int de){
dep[u]=de,sz[u]=1;
for(auto e:G[u]){
int v=e.to,w=e.cost;
if(v==fa[u])continue;
dis[v]=dis[u]+w,fa[v]=u,dfs1(v,de+1),sz[u]+=sz[v];
if(sz[v]>sz[hson[u]])hson[u]=v;
}
}
int tot=0;
void dfs2(int u,int tp){
top[u]=tp,dfn[u]=++tot,rk[dfn[u]]=u;
if(hson[u])dfs2(hson[u],tp);
for(auto e:G[u]){
int v=e.to,w=e.cost;
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
int getdis(int x){return T.sum(dfn[x]);}
int dist(int x,int y){
int z=LCA(x,y);
return getdis(x)+getdis(y)-getdis(z)*2;
}
void build(){
for(int i=1;i<=n;i++)T.add(i,dis[rk[i]]-dis[rk[i-1]]);
}
void add(int x,int k){
int l=dfn[x],r=dfn[x]+sz[x]-1;
T.add(l,k),T.add(r+1,-k);
}
};
struct Node{
int u,v;
Node(int U,int V):u(U),v(V){}
Node(){}
};
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
struct SegTree{
Node d[MN<<2];
inline void build(int l,int r,int p){
if(l==r){
d[p].u=d[p].v=HLD::rk[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,ls(p)),build(mid+1,r,rs(p));
pushup(p);
}
inline void pushup(int p){
int x=d[ls(p)].u,y=d[ls(p)].v;
int a=d[rs(p)].u,b=d[rs(p)].v;
int mx=HLD::dist(x,y),ax=x,ay=y;
int t=HLD::dist(x,a);if(t>mx)mx=t,ax=x,ay=a;
t=HLD::dist(x,b);if(t>mx)mx=t,ax=x,ay=b;
t=HLD::dist(y,a);if(t>mx)mx=t,ax=y,ay=a;
t=HLD::dist(y,b);if(t>mx)mx=t,ax=y,ay=b;
t=HLD::dist(a,b);if(t>mx)mx=t,ax=a,ay=b;
d[p].u=ax,d[p].v=ay;
}
inline void modify(int l,int r,int ql,int qr,int p){
if(l<=ql&&qr<=r)return ;
int mid=(ql+qr)>>1;
if(l<=mid)modify(l,r,ql,mid,ls(p));
if(r>mid)modify(l,r,mid+1,qr,rs(p));
pushup(p);
}
inline int get(){
return HLD::dist(d[1].u,d[1].v);
}
}Tree;
signed main(void){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
#endif
n=read(),q=read(),w=read();
for(int i=1;i<=n-1;i++){
int u=read(),v=read(),w=read();
G[u].push_back(Edge(v,w)),G[v].push_back(Edge(u,w));
fr[i]=u,to[i]=v,val[i]=w;
}
HLD::dfs1(1,1),HLD::dfs2(1,1),HLD::build();int lans=0;
Tree.build(1,n,1);
// cout<<HLD::getdis(1)<<" "<<HLD::getdis(2)<<" "<<HLD::getdis(3)<<" "<<HLD::getdis(4)<<endl;
// cout<<Tree.get()<<endl;
while(q--){
int d=(read()+lans)%(n-1)+1,e=(read()+lans)%w;
int u;
if(HLD::dep[fr[d]]>HLD::dep[to[d]])u=fr[d];
else u=to[d];
HLD::add(u,e-val[d]);val[d]=e;
Tree.modify(HLD::dfn[u],HLD::dfn[u]+HLD::sz[u]-1,1,n,1);
cout<<(lans=Tree.get())<<'\n';
}
return 0;
}