BZOJ 2843 极地旅行社

5 篇文章 0 订阅

Problem

BZOJ

Solution

lct。
建桥就是判一下findroot是否相等,不相等就link。
修改:先把自己的val更新,然后access更新标记,splay下放标记。
询问:先makeroot,再access一下就可以得到x,y的辅助树,然后splay之后输出sz[y]就是答案。
值得注意的是access操作的时候要pushup。

也有更优的做法,注意到只有link操作,可以离线操作,对于link操作树剖。

Code

#include <algorithm>
#include <cstdio>
#define pd(x) if(rev[x])pushdown(x)
using namespace std;
const int maxn=30010;
int n,m,x,y,top,val[maxn],f[maxn],ch[maxn][2],rev[maxn],sz[maxn],q[maxn];
char op[10];
void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+val[x];}
void pushdown(int x)
{
    if(ch[x][0]) rev[ch[x][0]]^=1;
    if(ch[x][1]) rev[ch[x][1]]^=1;
    swap(ch[x][0],ch[x][1]);
    rev[x]=0;
}
inline int isroot(int x){return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;}
void rotate(int x)
{
    int fa=f[x],ff=f[fa],l,r;
    if(ch[fa][0]==x) l=0;
    else l=1;r=l^1;
    if(!isroot(fa)){if(ch[ff][0]==fa) ch[ff][0]=x;else ch[ff][1]=x;}
    f[x]=ff;f[fa]=x;f[ch[x][r]]=fa;
    ch[fa][l]=ch[x][r];ch[x][r]=fa;
    pushup(fa);pushup(x);
}
void splay(int x)
{
    q[top=1]=x;
    for(int i=x;!isroot(i);i=f[i]) q[++top]=f[i];
    for(int i=top;i;i--) pd(q[i]);
    while(!isroot(x))
    {
        int fa=f[x],ff=f[fa];
        if(!isroot(fa))
        {
            if((ch[fa][0]==x)^(ch[ff][0]==fa)) rotate(x);
            else rotate(fa);
        }
        rotate(x);
    }
}
void access(int x){for(int t=0;x;t=x,x=f[x]) splay(x),ch[x][1]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=1;}
int find(int x){access(x);splay(x);while(ch[x][0]) x=ch[x][0];return x;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);if(ch[y][0]==x) ch[y][0]=0,f[x]=0;}
void link(int x,int y){makeroot(x);f[x]=y;}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&val[i]),sz[i]=val[i];
    scanf("%d",&m);
    while(m--)
    {
        scanf("%s%d%d",op,&x,&y);
        switch(op[0])
        {
            case 'b':
                if(find(x)==find(y)) puts("no");
                else puts("yes"),link(x,y);
                break;
            case 'p':access(x);splay(x);val[x]=y;pushup(x);break;
            case 'e':
                if(find(x)==find(y))
                  {makeroot(x);access(y);splay(y);printf("%d\n",sz[y]);}
                else puts("impossible");
                break;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值