一棵树支持三个操作。
①给链加等差数列
②查询链上的和
③回到第x次修改后
强制在线。
树剖+主席树。做完了。
注意这里要用到标记永久化。也就是说标记不下传,询问时直接拿来加。只有满足结合律才可以标记永久化。
典型的代码题。嘴巴可做,手写崩溃。
数组往死里开。反正我的代码,三千万太小、六千万开不了、四千万能过!
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 200005
#define NN 40000000
#define inf 1000000000000000LL
int n;LL ans;
int he[N],ne[N<<1],to[N<<1],tot;
int dep[N],sz[N],son[N],dad[N],pre[N],dfn[N],nfd[N],cnt;
int m,las,now,wz[N],rt[NN],id,lc[NN],rc[NN];LL la[NN],ld[NN],sum[NN];
int read(){
int x=0;char ch=G;
for(;ch<48||ch>57;ch=G);
for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
return x;
}
char readc(){
char ch=G;
while(ch<97||ch>122)ch=G;
return ch;
}
void add(int x,int y){
to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void DFS1(int x){
int y,i;dep[x]=dep[pre[x]]+1;sz[x]=1;
for(i=he[x];i;i=ne[i])if((y=to[i])!=pre[x]){
pre[y]=x;DFS1(y);
if(sz[y]>sz[son[x]])son[x]=y;sz[x]+=sz[y];
}
}
void DFS2(int x){
int y,i;dad[x]=son[pre[x]]==x?dad[pre[x]]:x;nfd[dfn[x]=++cnt]=x;
if(son[x])DFS2(son[x]);
for(i=he[x];i;i=ne[i])if(!dfn[y=to[i]])
DFS2(y);
}
int lca(int x,int y){
int fx=dad[x],fy=dad[y];
while(fx!=fy)
if(dep[fx]>dep[fy])fx=dad[x=pre[fx]];
else fy=dad[y=pre[fy]];
return dep[x]<dep[y]?x:y;
}
LL cal(LL a,LL b,LL x){
return (a+b)*x>>1;
}
void ins(int L,int R,LL a,LL d,int l,int r,int&num,int old){
la[num=++id]=la[old];ld[num]=ld[old];sum[num]=sum[old];
if(L<=l&&r<=R){
la[num]+=a+d*(l-L);ld[num]+=d;sum[num]+=cal(a+d*(l-L),a+d*(r-L),r-l+1);
lc[num]=lc[old];rc[num]=rc[old];
return;
}
int mid=l+r>>1;
if(L<=mid)ins(L,R,a,d,l,mid,lc[num],lc[old]);
else lc[num]=lc[old];
if(R>mid)ins(L,R,a,d,mid+1,r,rc[num],rc[old]);
else rc[num]=rc[old];
sum[num]=sum[lc[num]]+sum[rc[num]]+cal(la[num],la[num]+ld[num]*(r-l),r-l+1);
}
void query(int L,int R,int l,int r,int num){
if(!num)return;
if(l==L&&R==r){
ans+=sum[num];return;
}
ans+=cal(la[num]+ld[num]*(L-l),la[num]+ld[num]*(R-l),R-L+1);
int mid=l+r>>1;
if(L<=mid)query(L,min(R,mid),l,mid,lc[num]);
if(R>mid)query(max(L,mid+1),R,mid+1,r,rc[num]);
}
int main(){
int i,Q,x,y,z,fx,fy;char ch;LL a,d;
n=read();Q=read();
rep(i,2,n){
x=read();y=read();add(x,y);add(y,x);
}
DFS1(1);DFS2(1);
while(Q--){
ch=readc();
if(ch=='c'){
x=(read()+ans)%n+1;y=(read()+ans)%n+1;a=read();d=read();
z=lca(x,y);a-=d;
for(fx=dad[x];dep[fx]>dep[z];fx=dad[x=pre[fx]]){
a+=d*(dfn[x]-dfn[fx]+1);
ins(dfn[fx],dfn[x],a,-d,1,n,rt[++now],rt[las]);las=now;
}
if(dfn[z]<dfn[x]){
a+=d*(dfn[x]-dfn[z]);
ins(dfn[z]+1,dfn[x],a,-d,1,n,rt[++now],rt[las]);las=now;
}
a+=d*(dep[y]-dep[z]+2);
for(fy=dad[y];dep[fy]>dep[z];fy=dad[y=pre[fy]]){
a-=d*(dfn[y]-dfn[fy]+1);
ins(dfn[fy],dfn[y],a,d,1,n,rt[++now],rt[las]);las=now;
}
a-=d*(dfn[y]-dfn[z]+1);
ins(dfn[z],dfn[y],a,d,1,n,rt[++now],rt[las]);las=now;
wz[++m]=now;
}
else if(ch=='q'){
x=(read()+ans)%n+1;y=(read()+ans)%n+1;
ans=0;z=lca(x,y);
for(fx=dad[x];dep[fx]>dep[z];fx=dad[x=pre[fx]])
query(dfn[fx],dfn[x],1,n,rt[las]);
if(dfn[z]<dfn[x])query(dfn[z]+1,dfn[x],1,n,rt[las]);
for(fy=dad[y];dep[fy]>dep[z];fy=dad[y=pre[fy]])
query(dfn[fy],dfn[y],1,n,rt[las]);
query(dfn[z],dfn[y],1,n,rt[las]);
printf("%lld\n",ans);
}
else las=wz[(read()+ans)%(m+1)];
}
return 0;
}