@xiaoziyao
        
        2020-10-13T15:14:17.000000Z
        字数 3619
        阅读 1760
    解题报告
欧拉序+线段树维护好题。
对于一个直径,我们可以把它拆成两条链和,此时,我们要引入一个叫欧拉序的东西:
欧拉序与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 longconst 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;}