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);
}
}
}
}

Box HDU - 2475 (Splay 维护森林)的更多相关文章

  1. HDU - 2475:Box(splay维护森林)

    There are N boxes on the ground, which are labeled by numbers from 1 to N. The boxes are magical, th ...

  2. hdu 2475 BOX (splay)

    版权声明:本文为博主原创文章,未经博主允许不得转载. hdu 2475 Splay树是一种神奇的东西... 题意: 有一些箱子,要么放在地上,要么放在某个箱子里面 . 现在有两种操作: (1) MOV ...

  3. HDU 2475 BOX 动态树 Link-Cut Tree

    Box Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) [Problem De ...

  4. hdu 3436 splay树+离散化*

    Queue-jumpers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) To ...

  5. hdu 4453 splay

    Looploop Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  6. 【BZOJ 3729】3729: Gty的游戏 (Splay维护dfs序+博弈)

    未经博主同意不得转载 3729: Gty的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 448  Solved: 150 Description ...

  7. HNOI2004宠物收养所(splay维护二叉搜索树模板题)

    描述 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领 ...

  8. BZOJ 3729 splay维护DFS序+博弈论

    思路: 这像是 阶梯Nim之类的东西 我们 直接把sg函数 设成mod(L+1)的 一棵子树 向下的奇数层上的石子xor起来 就是答案 有加点和改值的操作 就splay维护一下 //By Sirius ...

  9. BZOJ 1492 [NOI2007]货币兑换Cash (CDQ分治/splay 维护凸包)

    题目大意:太长了略 splay调了两天一直WA弃疗了 首先,我们可以猜一个贪心,如果买/卖,就一定都买/卖掉,否则不买/卖 反正货币的行情都是已知的,没有任何风险,所以肯定要选择最最最优的方案了 容易 ...

随机推荐

  1. 【2019-08-29】让自己着眼当下,真TM不容易

    07:50 天是蓝色的,路面是灰色的,树是绿色的,那个奶茶店的招牌是白色的.我的表情是木讷的,老婆的表情是嫌弃的,那个路人的表情是无解的,地铁工作人员的表情是无奈的刚才回到公司看到那个通宵了的同事的表 ...

  2. HTTP之缓存命中

    缓存命中和缓存未命中 ========================摘自<HTTP权威指南>============================== 1.缓存命中和缓存未命中 可以用 ...

  3. vue 复制文本到剪切板上

    1.下载clipboard.js npm install vue-clipboard2 --save 2.引入,可以在mian.js中全局引入也可以在单个vue中引入 import Clipboard ...

  4. ForkJoin和流式操作

    Fork/Join框架:在必要的情况下,将一个大任务,进行拆分(fork) 成若干个子任务(拆到不能再拆,这里就是指我们制定的拆分的临界值),再将一个个小任务的结果进行join汇总. 采用juc包的f ...

  5. 23 Maven工程module的移除和重新导入

    1.移除module 移除后: 点击右侧的maven projects: 2.重新导入刚才移除的module (1)方法1 (2)方法2 Ctrl+Shift+ALT+S的快捷键 选择modules ...

  6. MySQL中的 redo 日志文件

    MySQL中的 redo 日志文件 MySQL中有三种日志文件,redo log.bin log.undo log.redo log 是 存储引擎层(innodb)生成的日志,主要为了保证数据的可靠性 ...

  7. ActiveMQ使用Zookeeper+LevelDb配置Master/Slave集群

    前言: 本文介绍的AMQ集群是Master-Slave模式的,官网介绍三种方案: (1)基于共享文件系统的,(2)基于JDBC,(3)基于可复制的LevelDB. 关于三种方式的对比网上已经有很多,本 ...

  8. 剑指Offer_Java_顺时针打印矩阵(二维数组)

    顺(逆)时针打印矩阵 算法思想: 简单来说,就是不断地收缩矩阵的边界 定义四个变量代表范围,up(初始0).down(初始-行高).left(初始-0).right(初始-列宽), 向右走存入整行的值 ...

  9. 重绘MenuStrip 控件

    重绘MenuStrip控件 效果如图: 首先添加 CustomProfessionalRenderer类 用于重绘控件菜单样式 /// <summary> /// 自定义MenuStrip ...

  10. 为什么改了JS数组中的一个元素的值,其他数组元素值都跟着变了

    原因: 数组是引用类型,数组变量存储在栈,元素数据存储在堆中,将数组赋值不同的对象,所以的赋值对象都指向堆同一个数据,所以改变其中一个数组中的元素,别的数组元素也会改变. 解决方案: 原理就是先把数组 ...