虽然这只是Sone0里很小的一部分,但是我认为这是最烦的一部分,对着一个错误的题目调了两天TAT(最后才发现自己的程序的轮换打反了)。
如果想直接用一棵LCT来做有一个最简单的想法,就是把x到y这段提取出来,然后再轮换一下。但是,这个想法明显有问题,因为轮换的时候只是换了一下相对顺序,并没有交换权值的大小,就是说在下一次询问编号的时候,原来的点x权值c,换了之后,还是会访问到点x和权值c。这样权值就根本没有换过。
我们现在就发现了,编号是一个很麻烦的东西。
所以,我们可以考虑一下,权值只维护相对位置,然后再次同时我们再维护一下它的编号,这样权值就可以和编号一一对应了。但是我们还是会发现这样是不能询问编号的,所以我们只能把编号打出来,再建一棵编号LCT,因为是从前面的权值LCT打出来的,那么这个权值LCT的中序遍历(相对顺序)和编号LCT的中序遍历(相对顺序)是一一对应的。因为要一一对应,所以我们在access的时候,两棵LCT要一起变动,换根的时候深度标记也要一起翻转。
因为编号LCT上的编号是不会变化的,编号和原树是一样的。
那么在询问编号x到编号y上的信息的时候,(因为两个LCT的相对顺序是一样的,所以access和makeroot的时候都是打在一起的,因为还要两个一起修改树的结构),先在树上把编号x到y放到一起,然后再寻找此时在权值LCT上对应的点,然后当前这个点的splay与x(或y)所在的splay是一一对应的,那么直接修改或查询即可。
轮换的时候,知道权值的那一段,然后直接修改权值的相对顺序就可以了。
看到这里,肯定有一个很明显的问题,怎样在编号LCT的x节点找到对应的权值LCT的节点。
我们记录一个g[0][x]和g[1][x]分别表示(0是权值的,1是编号的),权值LCTx对应编号LCT的根节点,编号LCTx对应权值LCT的根节点。我们知道LCT上有很多个虚边,那么头上是虚边的那个就是虚边下面splay的根节点,所以我们记录这些根节点一一对应,不是根节点的点没有g值。所以g要在access和轮换和rotate的时候更新。
找到对应的根节点之后就很好办了,因为找出来的那个splay是和当前被找的那个splay相对顺序一样的,所以在另外那么的splay找x的时候,只用找中序遍历为size[t[0][x]]+1(及x在0【或1】树上的中序遍历)的节点即可。
维护虚边的时候其实只用打一个数组,因为只有编号对应的LCT才是和原树的编号对应的。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
int i,j,k,l,n,m,ans,p,q,u;
int t[2][maxn][2],pfa[maxn],f[2][maxn],bz[2][maxn],d[maxn];
int first[maxn],last[maxn],next[maxn],num,x,y,g[2][maxn];
ll sum[2][maxn],ad[2][maxn],a[2][maxn],size[2][maxn],z;
char s[9];
void add(int x,int y){
last[++num]=y,next[num]=first[x],first[x]=num;
}
int son(int o,int x){return(t[o][f[o][x]][0]!=x);}
void update(int o,int x){
sum[o][0]=size[o][0]=0;
sum[o][x]=a[o][x]+sum[o][t[o][x][0]]+sum[o][t[o][x][1]];
size[o][x]=1+size[o][t[o][x][0]]+size[o][t[o][x][1]];
}
void gao(int o,int x,ll y){
sum[o][x]+=size[o][x]*y;a[o][x]+=y;ad[o][x]+=y;
}
void down(int o,int x){
if(bz[o][x]){
swap(t[o][x][0],t[o][x][1]);
bz[o][t[o][x][0]]^=1,bz[o][t[o][x][1]]^=1;bz[o][x]=0;
}
if(ad[o][x]){
gao(o,t[o][x][0],ad[o][x]),gao(o,t[o][x][1],ad[o][x]);ad[o][x]=0;
}
}
void remove(int o,int x,int y){
while(x!=y)d[++d[0]]=x,x=f[o][x];
while(d[0])down(o,d[d[0]--]);
}
void rotate(int o,int x){
int y=f[o][x],z=son(o,x),u=g[o][y];
f[o][t[o][y][z]=t[o][x][1-z]]=y;
t[o][f[o][x]=f[o][y]][son(o,y)]=x;
if(!f[o][x]&&o)pfa[x]=pfa[y],pfa[y]=0;
if(u)g[1-o][u]=x,g[o][x]=u,g[o][y]=0;
f[o][t[o][x][1-z]=y]=x;
update(o,y),update(o,x);
}
void splay(int o,int x,int y){
remove(o,x,y);
while(f[o][x]!=y){
if(f[o][f[o][x]]!=y)if(son(o,f[o][x])==son(o,x))rotate(o,f[o][x]);else rotate(o,x);
rotate(o,x);
}
}
int kth(int o,int x,int k){
down(o,x);down(1-o,x);if(size[o][t[o][x][0]]+1==k)return x;
if(size[o][t[o][x][0]]+1>k)return kth(o,t[o][x][0],k);return kth(o,t[o][x][1],k-size[o][t[o][x][0]]-1);
}
int find(int x){
splay(0,g[1][x],0);
return kth(0,g[1][x],size[1][t[1][x][0]]+1);
}
void access(int x){
int y=0,yy=0,u,p,q;
while(x){
splay(1,x,0);
u=find(x);splay(0,u,0);
p=t[1][x][1];f[1][p]=0;q=t[0][u][1];f[0][q]=0;
pfa[p]=x;g[0][g[1][p]=q]=p;g[0][g[1][x]=u]=x;
t[1][f[1][y]=x][1]=y,t[0][f[0][yy]=u][1]=yy,pfa[y]=g[1][y]=g[0][yy]=0;
update(1,x),update(0,u);
y=x,x=pfa[x];yy=u;
}
}
void makeroot(int x){
int u;access(x),splay(1,x,0);u=find(x);splay(0,u,0);bz[1][x]^=1;bz[0][u]^=1;
}
void dfs(int x,int y){
int i;
pfa[x]=y;size[0][x]=size[1][x]=1;g[0][x]=g[1][x]=x;
rep(i,x)if(last[i]!=y)dfs(last[i],x);
}
int main(){
freopen("shift.in","r",stdin);
freopen("shift.out","w",stdout);
scanf("%d",&n);
fo(i,1,n-1){
scanf("%d%d",&x,&y),add(x,y),add(y,x);
}
dfs(1,0);
for(scanf("%d",&m);m;m--){
scanf("%s%d%d",s,&x,&u);
makeroot(x);access(u);splay(1,u,0);
y=find(u);splay(0,y,0);
if(s[0]=='A'){
scanf("%lld",&z);
gao(0,y,z);
}
else if(s[0]=='Q')printf("%lld\n",sum[0][y]);
else{
p=kth(0,y,size[0][y]),q=kth(0,y,1);
if(p==q)continue;
splay(0,p,0);f[0][t[0][p][0]]=0,t[0][p][0]=0;
splay(0,q,0);f[0][t[0][p][1]=q]=p;g[1][u]=p;
update(0,q),update(0,p);
}
}
}