hdu 2475 Box splay, lct

Box

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2421    Accepted Submission(s): 737


Problem Description
There are N boxes on the ground, which are labeled by numbers from 1 to N. The boxes are magical, the size of each one can be enlarged or reduced arbitrarily.
Jack can perform the “MOVE x y” operation to the boxes: take out box x; if y = 0, put it on the ground; Otherwise, put it inside box y. All the boxes inside box x remain the same. It is possible that an operation is illegal, that is, if box y is contained (directly or indirectly) by box x, or if y is equal to x.
In the following picture, box 2 and 4 are directly inside box 6, box 3 is directly inside box 4, box 5 is directly inside box 1, box 1 and 6 are on the ground.

The picture below shows the state after Jack performs “MOVE 4 1”:

Then he performs “MOVE 3 0”, the state becomes:

During a sequence of MOVE operations, Jack wants to know the root box of a specified box. The root box of box x is defined as the most outside box which contains box x. In the last picture, the root box of box 5 is box 1, and box 3’s root box is itself.
 

Input
Input contains several test cases.
For each test case, the first line has an integer N (1 <= N <= 50000), representing the number of boxes.
Next line has N integers: a1, a2, a3, ... , aN (0 <= ai <= N), describing the initial state of the boxes. If ai is 0, box i is on the ground, it is not contained by any box; Otherwise, box i is directly inside box ai. It is guaranteed that the input state is always correct (No loop exists).
Next line has an integer M (1 <= M <= 100000), representing the number of MOVE operations and queries.
On the next M lines, each line contains a MOVE operation or a query:
1.  MOVE x y, 1 <= x <= N, 0 <= y <= N, which is described above. If an operation is illegal, just ignore it.
2.  QUERY x, 1 <= x <= N, output the root box of box x.
 

Output
For each query, output the result on a single line. Use a blank line to separate each test case.
 

Sample Input
  
  
2 0 1 5 QUERY 1 QUERY 2 MOVE 2 0 MOVE 1 2 QUERY 1 6 0 6 4 6 1 0 4 MOVE 4 1 QUERY 3 MOVE 1 4 QUERY 1
 

Sample Output
  
  
1 1 2 1 1
 

Source

利用splay伸展树+lct的部分操作实现

由于不能改变根,只留access操作即可。

方法:

1. 查询点v的根,直接access,然后找父亲

2.对于改变子树到别的结点下,记录每个子树的父亲, access(fa[u])这样u就和父亲分开了,

然后令u的父亲为空,这样就把u这个子树给拆下来了。

判断合法性,只需要判断v是的父亲是否是u即可。

合法就令u的父亲为v

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
#define maxn 200007
#define inf  1000000000
#define ll int

struct Node{
    Node *fa,*ch[2];
    bool root;
    int id;
};
Node pool[maxn];
Node *nil,*tree[maxn];
int cnt = 0;
void init(){
    cnt = 1;
    nil = tree[0] = pool;
    nil->ch[0] = nil->ch[1] = nil;
    nil->root = true;
    nil->fa = nil;
    nil->id = 0;
}
Node *newnode(int id,Node *f){
    pool[cnt].fa = f;
    pool[cnt].ch[0]=pool[cnt].ch[1]=nil;
    pool[cnt].id = id;
    pool[cnt].root = true;
    return &pool[cnt++];
}

//将结点x旋转至splay中父亲的位置******
void rotate(Node *x){
    Node *f = x->fa, *ff = f->fa;
    int t = (f->ch[1] == x);
    if(f->root)
        x->root = true, f->root = false;
    else ff->ch[ff->ch[1] == f] = x;
    x->fa = ff;
    f->ch[t] = x->ch[t^1];
    x->ch[t^1]->fa = f;
    x->ch[t^1] = f;
    f->fa = x;
}
//将结点x旋转至x所在splay的根位置******
void splay(Node *x){
    Node *f, *ff;
    while(!x->root ){
        f = x->fa,ff = f->fa;
        if(!f->root)
            if((ff->ch[1]==f)&&(f->ch[1] == x)) rotate(f);
            else rotate(x);
        rotate(x);
    }
}
//将x到树根的路径并成一条path******
Node *access(Node *x){
    Node *y = nil;
    while(x != nil){
        splay(x);
        x->ch[1]->root = true;
        (x->ch[1] = y)->root = false;
        y = x;
        x = x->fa;
    }
    return y;
}

char word[30];
Node* findroot(Node*x){
    if(x->ch[0] == nil)return x;
    return findroot(x->ch[0]);
}
Node*fa[maxn];
int main(){
    int n,q,u,v,tt=0;
    Node*x;
    while(scanf("%d",&n)!=EOF){
        if(tt)puts("");
        tt++;
        init();
        for(int i = 1;i <= n; i++){
            tree[i] = newnode(i,nil);
        }
        for(int i = 1;i <= n; i++){
            scanf("%d",&u);
            tree[i]->fa = tree[u];
            fa[i] = tree[u];
        }
        scanf("%d",&q);
        while(q--){
            scanf("%s",word);
            if(word[0] == 'Q'){
                scanf("%d",&u);
                x = access(tree[u]);
                x = findroot(x);
                printf("%d\n",x->id);
                splay(x);
            }
            else {
                scanf("%d%d",&u,&v);
                access(fa[u]);
                splay(tree[u]);
                tree[u]->fa = nil;
                x = access(tree[v]);

                if(findroot(x) == tree[u]){
                    splay(tree[u]);
                    tree[u]->fa = fa[u];
                }
                else {
                    tree[u]->fa = tree[v];
                    fa[u] = tree[v];
                }
            }
        }
    }
    return 0;
}
/*

2
0 1
50
QUERY 1
QUERY 2
MOVE 2 0
MOVE 1 2
QUERY 1
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值