半年没打LCT,够呛。。。
这题没有cut?
容易错的地方:
1. rotate(x)时最后确定x应是其父亲左儿子还是右儿子时,有可能它要成为splay的根,所以else后面还要if,(这里比较特殊还不能用isroot判
2. splay双旋时应该先下放祖父再下放父亲。
3. 不仅是access,凡是要用到左右儿子且左右儿子有区分是务必要pushdown,更改了儿子信息务必要update。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,q;
struct tree
{
int t,sum,id;
bool rev;
tree *s[2],*f;
tree(){t=sum=0;rev=0;s[0]=s[1]=f=NULL;}
bool son(){return f->s[1]==this;}
bool isroot(){return (!f)||(f->s[0]!=this&&f->s[1]!=this);}
void update(){sum=(s[0]?s[0]->sum:0)+(s[1]?s[1]->sum:0)+t;}
void lab(){rev^=1;swap(s[0],s[1]);}
void pushdown()
{
if(rev)
for(int i=0;i<=1;i++)
if(s[i]) s[i]->lab();
rev=0;
}
void rotate()
{
pushdown();
bool b=son()^1;
f->s[b^1]=s[b];
if(s[b]) s[b]->f=f;
s[b]=f;f=f->f;s[b]->f=this;
if(f&&f->s[0]==s[b]) f->s[0]=this;
else if(f&&f->s[1]==s[b]) f->s[1]=this;//point 1
s[b]->update();
update();
}
void splay()
{
while(!isroot())
if(f->isroot()) f->pushdown(),rotate();
else
{
f->f->pushdown();//point 2
f->pushdown();
if(f->son()^son()) rotate();
else f->rotate();
rotate();
}
}
void access(){for(tree *x=this,*y=NULL;x;y=x,x=x->f) x->splay(),x->pushdown(),x->s[1]=y,x->update();}//point 3
void makeroot(){access();splay();lab();}
void link(tree *y){makeroot();f=y;}
void split(tree *y){y->makeroot();access();splay();}
tree* findroot(){access();splay();tree *x=this;pushdown();for(;x->s[0];x=x->s[0],x->pushdown());return x;}
void modify(int c){splay();t=sum=c;}
}*a[30010];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
(a[i]=new tree)->modify(x);
a[i]->id=i;
}
char rs[15];
scanf("%d",&q);
while(q--)
{
int x,y;
scanf("%s%d%d",rs+1,&x,&y);
if(rs[1]=='e')
{
if(a[x]->findroot()!=a[y]->findroot()) {puts("impossible");continue;}
a[x]->split(a[y]);
printf("%d\n",a[x]->sum);
}
if(rs[1]=='b')
{
if(a[x]->findroot()!=a[y]->findroot()) puts("yes"),a[x]->link(a[y]);
else puts("no");
}
if(rs[1]=='p') a[x]->modify(y);
}
return 0;
}