[BZOJ2843]极地旅行社 LCT模板

半年没打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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值