Description
给出一棵点权有根树,要求:
1. 树上的路径区间加
2. 树上路径区间查询和
3. 树上路径整体旋转一位(如:原路径上的权值依次是这样的:1,2,3,4,操作完后变成:4,1,2,3)
n<=100000
链剖+splay
这里不讲
LCT
LCT上的splay维护的是形态,而我们权值轮换的同时形态没有发生改变
于是我们要新开一棵splay专门维护权值,而且满足中序遍历与形态splay一致。
当shift时,只在权值splay上操作一番。其他操作一起维护即可。时刻注意维护好形态splay的根与权值splay的根的一一映射。
细节注意:
- parent边可以只对形态splay维护,有关点权的信息可以只对权值splay维护。其余的两个都要分别维护。
- 时刻注意维护好形态splay的根与权值splay的根的一一映射(非常重要)。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,sta[N];
int f[2][N],a[2][N][2],size[2][N],p[N],fx[2][N];
ll tag[N],sm[N],key[N];
bool rev[2][N];
bool pd(int o,int x){return x==a[o][f[o][x]][1];}
void update(int o,int x)
{
size[o][x]=1+size[o][a[o][x][0]]+size[o][a[o][x][1]];
if(o==1) sm[x]=key[x]+sm[a[o][x][0]]+sm[a[o][x][1]];
}
void turn(int o,int x)
{
if(!x) return;
swap(a[o][x][0],a[o][x][1]);
rev[o][x]^=1;
}
void add(int x,ll z)
{
if(!x) return;
key[x]+=z,sm[x]+=size[1][x]*z,tag[x]+=z;
}
void down(int o,int x)
{
if(rev[o][x])
{
turn(o,a[o][x][0]);turn(o,a[o][x][1]);
rev[o][x]=0;
}
if(o==1 && tag[x])
{
add(a[o][x][0],tag[x]);add(a[o][x][1],tag[x]);
tag[x]=0;
}
}
void remove(int o,int x,int y)
{
for(;x!=y;x=f[o][x]) sta[++sta[0]]=x;
while(sta[0]) down(o,sta[sta[0]--]);
}
void rotate(int o,int x)
{
int y=f[o][x],z=pd(o,x);
f[o][x]=f[o][y];
if(f[o][y]) a[o][f[o][y]][pd(o,y)]=x;
else
{
if(o==0) p[x]=p[y],p[y]=0;
fx[o][x]=fx[o][y],fx[o][y]=0;
fx[1-o][fx[o][x]]=x;
}
a[o][y][z]=a[o][x][1-z];
if(a[o][x][1-z]) f[o][a[o][x][1-z]]=y;
f[o][y]=x,a[o][x][1-z]=y;
update(o,y);
}
void splay(int o,int x,int y=0)
{
remove(o,x,y);
for(;f[o][x]!=y;rotate(o,x))
if(f[o][f[o][x]]!=y) rotate(o,pd(o,x)==pd(o,f[o][x])?f[o][x]:x);
update(o,x);
}
int kth(int o,int x,int k)
{
if(size[o][a[o][x][0]]+1==k) return x;
down(o,x);
if(k<=size[o][a[o][x][0]]) return kth(o,a[o][x][0],k);
else return kth(o,a[o][x][1],k-1-size[o][a[o][x][0]]);
}
int find(int x)
{
if(!x) return 0;
splay(0,x);
int rk=size[0][a[0][x][0]]+1;
return kth(1,fx[0][x],rk);
}
void access(int x)
{
for(int y=0;x;y=x,x=p[x])
{
int u=find(x),v=find(y);
splay(0,x);
splay(1,u);
f[0][a[0][x][1]]=0,p[a[0][x][1]]=x;
f[1][a[1][u][1]]=0;
fx[0][a[0][x][1]]=a[1][u][1];
fx[1][a[1][u][1]]=a[0][x][1];
a[0][x][1]=y,f[0][y]=x,p[y]=0;
a[1][u][1]=v,f[1][v]=u;
update(0,x);
update(1,u);
}
}
void makeroot(int x)
{
access(x);
int u=find(x);
splay(0,x);splay(1,u);
turn(0,x);turn(1,u);
}
void link(int x,int y){makeroot(x);p[x]=y;}
int main()
{
freopen("shift.in","r",stdin);
freopen("shift.out","w",stdout);
int Q,x,y,z;
scanf("%d",&n);
fo(i,1,n) fx[0][i]=fx[1][i]=i;
fo(i,1,n-1) scanf("%d %d",&x,&y),link(x,y);
char ch;
for(scanf("%d\n",&Q);Q;Q--)
{
scanf("%c",&ch);
if(ch=='A')
{
scanf("DD %d %d %d\n",&x,&y,&z);
makeroot(x);
access(y);
splay(0,y);
int u=find(y);splay(1,u);
add(u,z);
}
if(ch=='Q')
{
scanf("UERY %d %d\n",&x,&y);
makeroot(x);
access(y);
splay(0,y);
int u=find(y);splay(1,u);
printf("%lld\n",sm[u]);
}
if(ch=='S')
{
scanf("HIFT %d %d\n",&x,&y);
if(x==y) continue;
makeroot(x);access(y);
int u=find(x),v=find(y);
splay(1,v);
int lsv=a[1][v][0];
fx[1][lsv]=fx[1][v],fx[0][fx[1][v]]=lsv,fx[1][v]=0;
f[1][lsv]=0,a[1][v][0]=0;
update(1,v);
splay(1,u);
f[1][v]=u,a[1][u][0]=v;
update(1,u);
}
}
return 0;
}