动态树
/************************************************************** Problem: 1180 User: lxy8584099 Language: C++ Result: Accepted Time:6400 ms Memory:2024 kb ****************************************************************/ /* 再复习一下LCT 就是一颗splay转来转去? 分虚边和实边 虚边的意思是 改点没有连接到儿子 但是儿子连接到父亲 连接的时候连接成虚边 一个点最多有一个实边 虚边没有上限 */ #include<bits/stdc++.h> #include<cstdio> #define lc (c[x][0]) #define rc (c[x][1]) using namespace std; const int N=30050; int n,m,tot,sta[N],top; int fa[N],c[N][2],sum[N],val[N]; bool turn[N]; void swap(int&a,int&b) {a^=b^=a^=b;} bool nroot(int x) {return c[fa[x]][0]==x||c[fa[x]][1]==x;} void pushup(int x) {sum[x]=sum[lc]+sum[rc]+val[x];} void pushdown(int x) { if(!turn[x]) return; turn[x]=0,turn[lc]^=1,turn[rc]^=1; swap(c[lc][0],c[lc][1]),swap(c[rc][0],c[rc][1]); } void rotate(int x) // 旋转的时候注意虚边 { int y=fa[x],z=fa[y],sx=c[y][1]==x,sy=c[z][1]==y,w=c[x][sx^1]; if(nroot(y)) c[z][sy]=x; fa[x]=z; fa[w]=y; c[y][sx]=w; fa[y]=x; c[x][sx^1]=y; pushup(y); pushup(x); } void splay(int x) // 先把x到nroot路径上的标记全排掉 // 这只是转到部分数的root,across之后才能转成全部树的root { int xx=x; sta[top=1]=xx; while(nroot(xx)) sta[++top]=xx=fa[xx]; while(top) pushdown(sta[top--]); while(nroot(x)) { int y=fa[x],z=fa[y]; if(nroot(y)) rotate(((c[y][0]==x)^(c[z][0]==y))?x:y); rotate(x); } } void across(int x) {for(int y=0;x;x=fa[y=x]) splay(x),rc=y,pushup(x);} // 每次转了之后 默认上一次的x节点为右儿子(实边) 这样确保能打通! // 可以尝试强制为左儿子 void mroot(int x) {across(x),splay(x),turn[x]^=1,swap(lc,rc);} // 因为强制右儿子 转上去后 一定是最深的 交换左右子树就变成最浅的了 int froot(int x) {across(x),splay(x);while(lc) x=lc;return x;} void link(int x,int y) {mroot(x);fa[x]=y;} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&val[i]),sum[i]=val[i]; scanf("%d",&m); while(m--) { int x,y; char ch[10]; scanf("%s%d%d",ch,&x,&y); if(ch[0]=='b') { if(froot(x)==froot(y)) puts("no"); else puts("yes"),link(x,y); } else if(ch[0]=='p') mroot(x),val[x]=y,pushup(x); else { if(froot(x)!=froot(y)) puts("impossible"); else mroot(x),across(y),splay(y),printf("%d\n",sum[y]); } } return 0; }