@xiaoziyao
2020-10-13T23:14:17.000000Z
字数 3619
阅读 1261
解题报告
欧拉序+线段树维护好题。
对于一个直径,我们可以把它拆成两条链和,此时,我们要引入一个叫欧拉序的东西:
欧拉序与dfs序很类似,对于每个结点,在进入这个结点子树时记录一遍欧拉序,每一次从儿子子树中出来时也记录一遍欧拉序。
下面给出记录欧拉序的代码:
void dfs(int x,int last){
q[++qs]=x,in[x]=qs;
for(int i=start[x];i;i=then[i]){
int y=to[i];
if(y==last)
continue;
dfs(y,x);
q[++qs]=x;
}
out[x]=qs;
}
其中为欧拉序组成的序列,为进入子树时的欧拉序,则为出子树时的欧拉序。
这种序列有什么性质呢?
有了这个欧拉序,我们就相当于把这个树拍平了(类似于dfs序),我们来看这两个操作:
维护直径具体操作:
维护当前区间的最大深度,最小深度;维护一个深度差,表示左边是深度深的点,右边是深度浅的点,它们的最大是多少,同理维护一个深度差,表示左边是深度浅的点,右边是深度深的点,它们的最大是多少,这两个东西可以很轻松的完成维护。
然后,我们维护一个路径长度,代表左边一个深度深的点,中间一个深度浅的点(),右边一个深度深的点,它们的路径长度最长是多少。这个可以继承左右区间的,也可以用左区间的和右区间的来合并,或者用左区间的和右区间的合并。
维护上述值的代码:
inline void pushup(int now){
maxd[now]=max(maxd[lc[now]],maxd[rc[now]]);
mind[now]=min(mind[lc[now]],mind[rc[now]]);
lm[now]=max(max(lm[lc[now]],lm[rc[now]]),maxd[lc[now]]-2*mind[rc[now]]);
mr[now]=max(max(mr[lc[now]],mr[rc[now]]),maxd[rc[now]]-2*mind[lc[now]]);
lmr[now]=max(max(lmr[lc[now]],lmr[rc[now]]),max(lm[lc[now]]+maxd[rc[now]],maxd[lc[now]]+mr[rc[now]]));
}
边权很大,记得开。
完整代码:
#include<stdio.h>
#define int long long
const int maxn=100005;
int n,m,w,qs,e,lastans;
int start[maxn],to[maxn<<1],then[maxn<<1],worth[maxn<<1],id[maxn<<1],dis[maxn],in[maxn],out[maxn],q[maxn<<1],tid[maxn],val[maxn],maxd[maxn<<3],mind[maxn<<3],lm[maxn<<3],mr[maxn<<3],lmr[maxn<<3],lc[maxn<<3],rc[maxn<<3],lazy[maxn<<3];
inline int max(int a,int b){
return a>b? a:b;
}
inline int min(int a,int b){
return a<b? a:b;
}
inline void add(int x,int y,int z,int i){
then[++e]=start[x],start[x]=e,to[e]=y,worth[e]=z,id[e]=i;
}
void dfs(int x,int last){
q[++qs]=x,in[x]=qs;
for(int i=start[x];i;i=then[i]){
int y=to[i];
if(y==last)
continue;
dis[y]=dis[x]+worth[i];
tid[id[i]]=y;
dfs(y,x);
q[++qs]=x;
}
out[x]=qs;
}
inline void pushup(int now){
maxd[now]=max(maxd[lc[now]],maxd[rc[now]]);
mind[now]=min(mind[lc[now]],mind[rc[now]]);
lm[now]=max(max(lm[lc[now]],lm[rc[now]]),maxd[lc[now]]-2*mind[rc[now]]);
mr[now]=max(max(mr[lc[now]],mr[rc[now]]),maxd[rc[now]]-2*mind[lc[now]]);
lmr[now]=max(max(lmr[lc[now]],lmr[rc[now]]),max(lm[lc[now]]+maxd[rc[now]],maxd[lc[now]]+mr[rc[now]]));
}
inline void getlazy(int now,int v){
maxd[now]+=v,mind[now]+=v;
lm[now]-=v,mr[now]-=v;
lazy[now]+=v;
}
inline void pushdown(int now){
if(lazy[now]==0)
return ;
getlazy(lc[now],lazy[now]),getlazy(rc[now],lazy[now]);
lazy[now]=0;
}
void build(int l,int r,int now){
if(l==r){
getlazy(now,dis[q[l]]);
return ;
}
int mid=(l+r)>>1;
lc[now]=now<<1,rc[now]=now<<1|1;
build(l,mid,lc[now]),build(mid+1,r,rc[now]);
pushup(now);
}
void update(int l,int r,int now,int L,int R,int v){
if(L<=l&&r<=R){
getlazy(now,v);
return ;
}
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid)
update(l,mid,lc[now],L,R,v);
if(mid<R)
update(mid+1,r,rc[now],L,R,v);
pushup(now);
}
signed main(){
scanf("%lld%lld%lld",&n,&m,&w);
for(int i=1;i<n;i++){
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,z,i),add(y,x,z,i);
val[i]=z;
}
dfs(1,0);
build(1,qs,1);
for(int i=1;i<=m;i++){
int x,y;
scanf("%lld%lld",&x,&y);
x=(x+lastans)%(n-1)+1,y=(y+lastans)%w;
update(1,qs,1,in[tid[x]],out[tid[x]],y-val[x]);
val[x]=y,lastans=lmr[1];
printf("%lld\n",lastans);
}
return 0;
}