Description
Data Constraint
Solution
看到SHIFT操作,很显然就想到了splay中的翻转操作,还在树上,我们就考虑LCT。
但想了一会我们发现,直接SHIFT操作会破坏LCT树中的点与点的连接关系。
于是我们考虑维护两颗LCT,一颗维护树的形态,一颗维护树中的权值,保证对于一个维护树的形态的LCT中的splay,维护树中权值的LCT中都有一个大小相同的与之对应的splay,且这两个splay的中序遍历恰好使得每个编号都对应回自己的权值。对于一个SHIFT,我们就只翻转权值树中的点,这样就保证了在翻转同时不破坏树的形态。
那问题又来了,我们如何维护这两个LCT树之间的关系?对于一个编号,我们如何知道他在权值LCT中的位置呢?
对于每个操作,如access,makeroot等,我们可以同时对这两个LCT进行操作。那么我们对于一个编号,由于保证了对于一个编号splay的中序遍历,都有一个权值splay中的中序遍历与之相同,我们可以维护这个编号splay在权值LCT中的splay是哪个,然后我们按照当前编号在编号LCT中的splay的中序遍历的位置x,在对应的权值LCT中按中序遍历找一下第x个就好了。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=2e5+5;
int fa[maxn],pfa[maxn],f[maxn][2],bz[maxn],bz3[maxn],size[maxn],p[maxn];
int first[maxn],last[maxn],next[maxn],fa1[maxn],g[maxn][2],bz1[maxn];
int n,m,i,t,j,k,l,x,y,num,xx,yy,d[maxn],bz4[maxn];
ll sum[maxn],bz2[maxn],size1[maxn],b[maxn],z;
char s[20];
void bfs(){
int i=0,j=1,x;d[1]=1;
while (i<j){
x=d[++i];size1[x]=size[x]=1;p[x]=x;
for (t=first[x];t;t=next[t])
if (!size[last[t]]) d[++j]=last[t],pfa[d[j]]=x;
}
}
void change1(int x){
int y=g[x][0],z=g[x][1];
if (bz1[x]) swap(g[y][0],g[y][1]),swap(g[z][0],g[z][1]),bz1[y]=1-bz1[y],bz1[z]=1-bz1[z],bz1[x]=0;
if (bz2[x]) b[y]+=bz2[x],b[z]+=bz2[x],sum[y]+=size1[y]*bz2[x],sum[z]+=size1[z]*bz2[x],bz2[y]+=bz2[x],bz2[z]+=bz2[x],bz2[x]=0;
}
bool son(int x){return f[fa[x]][1]==x;}
bool son1(int x){return g[fa1[x]][1]==x;}
void change(int x){
int y=f[x][0],z=f[x][1];
if (bz[x]) swap(f[y][0],f[y][1]),swap(f[z][0],f[z][1]),bz[y]=1-bz[y],bz[z]=1-bz[z],bz[x]=0;
if (bz3[x]) p[y]=bz3[y]=p[z]=bz3[z]=bz3[x],bz3[x]=0;
}
void move(int x,int y){
while (x!=y) d[++d[0]]=x,x=fa[x];
for (;d[0];d[0]--) change(d[d[0]]);
}
void move1(int x,int y){
while (x!=y) d[++d[0]]=x,x=fa1[x];
for (;d[0];d[0]--) change1(d[d[0]]);
}
void rotate(int x){
size[x]=size[f[x][0]]+size[f[x][1]]+1;
}
void rotate1(int x){
int y=g[x][0],z=g[x][1];size1[x]=size1[y]+size1[z]+1;sum[x]=sum[y]+sum[z]+b[x];
}
void make(int x){
int y=fa[x],z=son(x);
f[fa[y]][son(y)]=x;fa[x]=fa[y];swap(pfa[x],pfa[y]);
fa[f[y][z]=f[x][1-z]]=y;fa[f[x][1-z]=y]=x;rotate(y);rotate(x);
}
void make1(int x){
int y=fa1[x],z=son1(x);
g[fa1[y]][son1(y)]=x;fa1[x]=fa1[y];
fa1[g[y][z]=g[x][1-z]]=y;fa1[g[x][1-z]=y]=x;rotate1(y);rotate1(x);
}
int splay(int x,int y){
move(x,y);
while (fa[x]!=y){
if (fa[fa[x]]!=y)
if (son(x)==son(fa[x])) make(fa[x]);
else make(x);
make(x);
}
}
int splay1(int x,int y){
move1(x,y);
while (fa1[x]!=y){
if (fa1[fa1[x]]!=y)
if (son1(x)==son1(fa[x])) make1(fa1[x]);
else make1(x);
make1(x);
}
}
int find2(int x,int sum){
change1(x);
while (sum!=size1[g[x][0]]+1){
if (size1[g[x][0]]+1<sum) sum-=size1[g[x][0]]+1,x=g[x][1];
else x=g[x][0];
change1(x);
}
return x;
}
int find(int x){
splay(x,0);
return find2(p[x],size[f[x][0]]+1);
}
void access(int x,int xx){
int y=0,yy=0;splay(x,0);
while (x){
splay1(xx,0);
fa[f[x][1]]=0;pfa[f[x][1]]=x;p[f[x][1]]=bz3[f[x][1]]=g[xx][1];fa[f[x][1]=y]=x;pfa[y]=0;rotate(x);
fa1[g[xx][1]]=0;fa1[g[xx][1]=yy]=xx;rotate1(xx);
y=x,x=pfa[x];yy=xx;if (x)xx=find(x);
}
}
void makeroot(int xx,int x){
access(x,xx);splay(x,0);
bz[x]=1-bz[x];swap(f[x][0],f[x][1]);splay1(xx,0);bz1[xx]=1-bz1[xx];swap(g[xx][0],g[xx][1]);p[x]=bz3[x]=xx;
}
void lian(int x,int y){
last[++num]=y;next[num]=first[x];first[x]=num;
}
int main(){
freopen("shift.in","r",stdin);freopen("shift.out","w",stdout);
scanf("%d",&n);
for (i=1;i<n;i++)
scanf("%d%d",&x,&y),lian(x,y),lian(y,x);
bfs();
scanf("%d\n",&m);
for (i=1;i<=m;i++){
scanf("%s%d%d",s+1,&x,&y);
xx=find(x);yy=find(y);
if (s[1]=='A'){
scanf("%lld",&z);
makeroot(xx,x);
access(y,yy);
splay1(xx,0);splay(x,0);p[x]=bz3[x]=xx;
bz2[xx]+=z;sum[xx]+=z*size1[xx];b[xx]+=z;
}else if (s[1]=='Q'){
makeroot(xx,x);
access(y,yy);splay1(xx,0);splay(x,0);
printf("%lld\n",sum[xx]);p[x]=bz3[x]=xx;
}else{
makeroot(xx,x);access(y,yy);splay1(yy,0);swap(g[yy][0],g[yy][1]);splay(y,0);p[y]=bz3[y]=yy;
}
scanf("\n");
}
}