hdu2475 Box(splay/lct)

这题好神呀。lct做法参见:传送门
这里说说splay做法。我们考虑一棵树的dfs序。进点x的时候记下x,出点x的时候记下x+n。则x的子树就是区间[x,x+n]。则操作1就相当于删除一个区间的数,然后把这一整个区间的数插入一个数的后面。x节点所在的根就是dfs序最前面的那个节点。然后就可以做了,不过需要奇怪的splay姿势【再见】

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define N 50010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,fa[N<<1],c[N<<1][2],a[N<<1],tot=0,root,h[N],num=0;
bool f[N],blank=0;
struct edge{
    int to,next;
}data[N];
inline void add(int x,int y){
    data[++num].to=y;data[num].next=h[x];h[x]=num;
}
inline void dfs(int x){
    a[++tot]=x;
    for(int i=h[x];i;i=data[i].next) dfs(data[i].to);
    a[++tot]=x+n;
}
inline void build(int &p,int l,int r){
    int mid=l+r>>1;p=a[mid];
    if(l<mid) build(c[p][0],l,mid-1),fa[c[p][0]]=p;
    if(r>mid) build(c[p][1],mid+1,r),fa[c[p][1]]=p;
}
inline void rotate(int x){
    int y=fa[x],z=fa[y],l=x==c[y][1],r=l^1;
    if(z) c[z][y==c[z][1]]=x;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;
}
inline void splay(int x,int k){
    while(fa[x]!=k){
        int y=fa[x],z=fa[y];
        if(fa[y]!=k){
            if(x==c[y][1]^y==c[z][1]) rotate(x);
            else rotate(y);
        }rotate(x);
    }
}
inline int find(int x){
    splay(x,0);while(c[x][0]) x=c[x][0];return x;
}
inline void move(int x,int y){
    if(x==y) return;
    splay(x,0);splay(x+n,x);
    for(int i=y;i;i=fa[i]) if(i==c[x+n][0]) return;
    int xx=c[x][0],yy=c[x+n][1];c[x][0]=c[x+n][1]=fa[xx]=fa[yy]=0;
    if(xx&&yy){
        while(c[yy][0]) yy=c[yy][0];c[yy][0]=xx;fa[xx]=yy;
    }if(!y) return;
    splay(y,0);int succ=c[y][1];while(c[succ][0]) succ=c[succ][0];
    splay(succ,y);c[succ][0]=x;fa[x]=succ;
}
int main(){
//  freopen("a.in","r",stdin);
    while(~scanf("%d",&n)){
        if(!blank) blank=1;else puts("");memset(f,0,sizeof(f));
        memset(h,0,sizeof(h));num=0;
        memset(fa,0,sizeof(fa));memset(c,0,sizeof(c));
        for(int i=1;i<=n;++i){
            int x=read();if(!x) f[i]=1;
            else add(x,i);
        }for(int i=1;i<=n;++i){
            if(!f[i]) continue;tot=0;dfs(i);build(root,1,tot);
        }m=read();
        while(m--){
            char op[10];scanf("%s",op+1);int x=read();
            if(op[1]=='Q') printf("%d\n",find(x));
            else move(x,read());
        }
    }return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值