• [题解] hdu 2475 Box(Splay)


    - 传送门 -

     http://acm.hdu.edu.cn/showproblem.php?pid=2475
     

    # Box

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

    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

    [Statistic](http://acm.hdu.edu.cn/statistic.php?pid=2475) | [Submit](http://acm.hdu.edu.cn/submit.php?pid=2475) | [Discuss](http://acm.hdu.edu.cn/discuss/problem/list.php?problemid=2475) | [Note](http://acm.hdu.edu.cn/note/note.php?pid=2475)
      ### - 题意 -  有 n 个盒子, 题目一开始会告诉你每个盒子外层的盒子, 有以下两种操作:  MOVE a b : 把盒子 a (连同 a 盒子内部的盒子子)放入盒子 b .  QUERY a : 查询盒子 a 最外层的盒子.   ### - 思路 -  对每个最外层盒子建树, 将每个盒子视做两个节点[k], [k+n] (也可以看成一对括号), 其中的盒子就在这两个节点之间.  MOVE a b 操作就将表示 a 盒子的两个节点旋到rt, c[rt][1], 然后切下来, 将剩下的两部分(根为c[rt][0], c[c[rt][1]][1]) 合并为一颗, 再把切下来的部分插入到 b 和 b的后继节点 之, 此时要注意: 判断 b 是否在 a 盒子中, 判断 a == b ?  Q a 操作就先旋 a 到根再找树上第一个节点.  建树过程中可将同一级别的盒子(外层盒子相同或没有)用链表穿起来, 对于没有外层盒子的盒子用一个额外的数组记录然后以他们为根建树, 建树的本质是一条只有右儿子的链.    细节见代码.

     PS :
     1. 做了一天却被 Dalao 嘲讽是水题 手动微笑...我能怎么办, 我也很绝望啊...
     2. 这道题将盒子的包含关系转化为点的包含关系很适合拓宽脑洞.
     

    - 代码 -

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int M = 1e5 + 5;
    const int N = 1e5 + 5;
    
    int head[M], pr[M], NEXT[M];
    int f[M], c[M][2];
    int n, m, g, h; 
    
    char st[10]; 
    
    void read(int &x) {
    	x = 0; int f = 1; char ch = getchar();
    	while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); }
    	x *= f;
    }
    
    void Init() {
    	memset(f, 0, sizeof f);
    	memset(c, 0, sizeof c);
    	memset(head, 0, sizeof head);
    	memset(NEXT, 0, sizeof NEXT);
    }
    
    void Add(int in, int out) {
    	NEXT[in] = head[out];
    	head[out] = in;
    }
    
    void Build(int x) {
    	f[x] = g;
    	c[g][1] = x;
    	g = x;
    	for (int i = head[x]; i; i = NEXT[i]) {
    		h = i;
    		Build(i);
    	}
    	f[x + n] = g;
    	c[g][1] = x + n;
    	g = x + n; //当一个盒子内部的盒子全部插入完之后, 就可以插入它的另一个节点了
    }
    
    void rotate(int x) {
      int y = f[x], z = f[y];
      int l = c[y][1] == x, r = l ^ 1;
      if (z) c[z][c[z][1] == y] = x;
      f[x] = z; f[y] = x; f[c[x][r]] = y;
      c[y][l] = c[x][r]; c[x][r] = y;
    }
    
    void Splay(int x,int k) {
      if (x != k)
      	while (f[x] != k) rotate(x);
    }
    
    void Solve(int a) {
    	Splay(a, 0);
    	for (; c[a][0]; a = c[a][0]);
    	printf("%d
    ",a);
    }
    
    void Move(int a, int b) {
    	if (a == b) return; //第一种非法情况:a == b
    	Splay(a, 0), Splay(a + n, a);
        for(int i = b; i; i = f[i])
          if(c[a + n][0] == i)  
              return ; //第二种非法情况: b 在 a 到 a+n 之间
    	int x = c[a][0], y = c[a + n][1];
    	f[x] = f[y] = c[a][0] = c[a + n][1] = 0;
    	if (x && y) {
    		for (; c[y][0]; y = c[y][0]);
    		c[y][0] = x;
    		f[x] = y; //合并
    	}
    	if(!b) return; //得到最外层盒子是 a 的盒子就可以了
    	int i;
    	Splay(b, 0);
    	for (i = c[b][1]; c[i][0]; i = c[i][0]);
    	Splay(i, b);
    	f[a] = i;
    	c[i][0] = a; // 插入
    }
    
    int main() {
    	int tmp = 0, keep = 0;
    	while (~scanf("%d",&n)) {
    		
    		if (keep ++) puts("");
    
    		Init();
    		for (int i = 1; i <= n; i++) {
    			read(h);
    			if (h) Add(i, h); //将同级别盒子用链表串起来
    			else {
    				pr[tmp] = i;  
    		    pr[i] = -1;
    		    tmp = i; //记录最外层的盒子以建树
    			}
    		}
    		for(int i = pr[0]; i != -1; i = pr[i])    
            g = 0, Build(i);
    		read(m);
    		while (m --) {
    			scanf("%s",st);
    			if (st[0] == 'Q') read(h), Solve(h);
    			else read(g), read(h), Move(g, h);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    从头开始搭建分布式日志平台的docker环境
    spring mvc+ELK从头开始搭建日志平台
    两个与spring事务相关的问题
    shiro realm 注解失败问题解决过程
    如何解决CRUD操作中与业务无关的字段赋值
    通过angularjs的directive以及service来实现的列表页加载排序分页
    项目中应用eventbus解决的问题
    统一配置中心
    java枚举与.net中的枚举区别
    列表页的动态条件搜索
  • 原文地址:https://www.cnblogs.com/Anding-16/p/7154133.html
Copyright © 2020-2023  润新知