首页 > 技术文章 > Box HDU - 2475 (Splay 维护森林)

Jiaaaaaaaqi 2019-10-18 00:07 原文

Box

\[Time Limit: 5000 ms \quad Memory Limit: 32768 kB \]

题意

给出 \(n\) 个箱子的包含关系,每次两种操作。
操作 \(1\):把 \(x\) 的箱子及里面的箱子一块挪到 \(y\) 箱子里面去。
操作 \(2\):查询 \(x\) 箱子的最外层的箱子编号。

思路

对于每一大块箱子,可以看成树和子树的包含关系,那么可以根据树的 \(dfs\) 序,把一个箱子所包含的箱子拍成一个区间,这样就变成了很多颗树。为了方便后面的操作,对于每个箱子 \(x\) 所包含的区间,用标号 \(x\) 来表示开始的位置,\(x+n\) 来表示结束的位置。

使用 \(splay\) 维护每多颗树的 \(dfs\) 序。由于每棵树都有一个自己的 \(root\) 节点,我们让他们的 \(root\) 节点统一连向 \(0\) 这个虚点。

再来看一看操作,操作 \(1\) 可以变成删除操作以及区间移动操作。操作 \(2\) 就是普通的查询操作。

对于操作 \(1\),先找到 \(x\)\(x+n\) 所在的位置,把 \(x\) \(splay\) 到其树的 \(root\) 上,把 \(x+n\) \(slay\)\(x\) 的右子树上,那么我们要转移的树就是 \(x->x+n->x+n\)的所有左子树。 同样的,要查找非法条件,只要看 \(y\) 在不在这棵树里面就可以了。
最后只要把这棵树插到标号 \(y\) 的右边就可以了。可以先把 \(y\) \(splay\) 到其 \(root\) 上,然后找到 \(y\) 下标意义上的后继,然后插入就行了。

对于操作\(2\),只要把 \(x\) \(splay\) 到其树的 \(root\) 上,然后查询这棵树里面的最小标号是多少,也就找到了最外的箱子的标号。

/*************************************************************** 
  > File Name    : a.cpp
  > Author       : Jiaaaaaaaqi
  > Created Time : Mon 14 Oct 2019 07:20:55 PM CST
 ***************************************************************/

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pb         push_back
#define  pii        pair<int, int>

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

vector<int> vv[maxn];
int root, tot;
int ch[maxn][2];
int sz[maxn], fa[maxn], val[maxn], cnt[maxn];
int a[maxn], id[maxn];

void init() {
	tol = root = tot = 0;
	for(int i=0; i<=n; i++) {
		vv[i].clear();
	}
} 

int newnode(int x, int f) {
	mes(ch[++tot], 0);
	val[tot] = x;
	id[x] = tot;
	fa[tot] = f;
	sz[tot] = cnt[tot] = 1;
	return tot;
}

void pushdown(int x) { }

void pushup(int x) {
	if(x) {
		sz[x] = cnt[x];
		if(ch[x][0])	sz[x] += sz[ch[x][0]];
		if(ch[x][1])	sz[x] += sz[ch[x][1]];
	}
}

int get(int x) {
	return ch[fa[x]][1] == x;
}

void rotate(int x) {
	int f = fa[x], gf = fa[f], k = get(x), w = ch[x][k ^ 1];
	pushdown(f), pushdown(x);
	ch[f][k] = w, fa[w] = f;
	ch[gf][get(f)] = x, fa[x] = gf;
	ch[x][k ^ 1] = f, fa[f] = x;
	pushup(f), pushup(x);
}

void splay(int x, int goal = 0) {
	int f, gf;
	while (fa[x] != goal) {
		f = fa[x], gf = fa[f];
		pushdown(gf), pushdown(f), pushdown(x);
		if (gf != goal) {
			if(get(x) == get(f)) rotate(f);
			else rotate(x);
		}
		rotate(x);
	}
	if (!goal) root = x;
}

int build(int l, int r, int f) {
	if(l > r)	return 0;
	int mid = l+r>>1;
	int now = newnode(a[mid], f);
	ch[now][0] = build(l, mid-1, now);
	ch[now][1] = build(mid+1, r, now);
	pushup(now);
	return now;
}

void dfs(int u) {
	a[tol++] = u;
	for(auto v : vv[u]) {
		dfs(v);
	}
	a[tol++] = u+n;
}

void Move(int a, int b) {
	if(a == b)	return ;
	int x = id[a], y = id[a+n], z = id[b];
	splay(x), splay(y, x);
	while(z && z!=y) {
		if(ch[y][0] == z)	return ;
		z = fa[z];
	}
	if(ch[x][0]==0 || ch[y][1]==0) {
		fa[ch[x][0]+ch[y][1]] = 0;
	} else {
		int k = ch[y][1];
		while(ch[k][0])	k = ch[k][0];
		splay(k, y);
		int cur = ch[y][1];
		ch[cur][0] = ch[x][0];
		fa[ch[x][0]] = cur;
		fa[cur] = 0;
		pushup(cur);
	}
	ch[x][0] = ch[y][1] = 0;
	if(b == 0)	return ;
	z = id[b];
	splay(z);
	if(ch[z][1]) {
		z = ch[z][1];
		while(ch[z][0])	z = ch[z][0];
	}
	ch[z][0] = x;
	fa[x] = z;
	pushup(z);
}

void Query(int x) {
	x = id[x];
	splay(x);
	while(ch[x][0])	x = ch[x][0];
	printf("%d\n", val[x]);
}

int main() {
	// freopen("in", "r", stdin);
	int flag = 0;
	while(~scanf("%d", &n)) {
		if(flag)	printf("\n");
		flag = 1;
		init();
		for(int i=1; i<=n; i++) {
			int x;
			scanf("%d", &x);
			vv[x].pb(i);
		}
		dfs(0);
		tol--;
		// for(int i=1; i<tol; i++)	printf("%d%c", a[i], i==tol-1 ? '\n':' ');
		int st = 1, c = 0;
		for(int i=1; i<tol; i++) {
			if(a[i] <= n)	c++;
			else	c--;
			if(c == 0) {
				build(st, i, 0);
				st = i+1;
			}
		}
		// for(int i=1; i<=tot; i++)	printf("val[%d] = %d\n", i, val[i]);
		scanf("%d", &m);
		char s[10];
		while(m--) {
			int x, y;
			scanf("%s", s+1);
			if(s[1] == 'M') {
				scanf("%d%d", &x, &y);
				Move(x, y);
			} else {
				scanf("%d", &x);
				Query(x);
			}
		}
	}
}

推荐阅读