[SCOI2014]方伯伯的OJ
这里是洛谷题目链接:[SCOI2014]方伯伯的OJ
题目描述
方伯伯正在做他的Oj。现在他在处理Oj上的用户排名问题。Oj上注册了n个用户,编号为1~n“,一开始他们按照编号排名。
方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号:
1.操作格式为1 x y,意味着将编号为x的用户编号改为y,而排名不变,执行完该操作后需要输出该用户在队列中的位置,数据保证x必然出现在队列中,同时1,是一个当前不在排名中的编号。
2.操作格式为2 x,意味着将编号为x的用户的排名提升到第一位,执行完该操作后需要输出执行该操作前编号为z用户的排名。
3.操作格式为3 x,意味着将编号为z的用户的排名降到最后一位,执行完该操作后需要输出执行该操作前编号为z用户的排名。
4.操作格式为4 k,意味着查询当前排名为k的用户编号,执行完该操作后需要输出当前操作用户的编号。
但同时为了防止别人监听自己的工作,方伯伯对他的操作进行了加密,即将四种操作的格式分别改为了:
- 1 x+a y+a
- 2 x+a
- 3 x+a
- 4 k+a
- 其中a为上一次操作得到的输出,一开始a=0。
例如:上一次操作得到的输出是5这一次操作的输入为:1 13 15因为这个输入是经过加密后的,所以你应该处理的操作是1 8 10现在你截获了方伯伯的所有操作,希望你能给出结果。
输入输出格式
输入格式:
输入的第1行包含2个用空格分隔的整数n和m,表示初始用户数和操作数。此后有m行,每行是一个询问,询问格式如上所示。
输出格式:
输出包含m行。每行包含一个整数,其中第i行的整数表示第i个操作的输出。
输入输出样例
说明
对于 100% 的数据,1 <= n <= 10^8,1 <= m <= 10^5
输入保证对于所有的操作 1,2,3,x 必然已经出现在队列中,同时对于所有操作 1,1 <= y <= 2 * 10^8,并且
y 没有出现在队列中。
对于所有操作 4,保证 1 <= k <= n。
先推荐一下巨佬同学oldfish的博客:[SCOI2014]方伯伯的OJ(偶尔会上不了)
首先看到了这个神奇的N,很显然是不能开10^8个节点来保存下所有的节点,再看M只有10^5,意思就是最多我只会用到10^5个点,但是事先我并不知道这些点是什么,所以也不能直接开10^5个节点,那么我们想应该如何才能保存下这些点.因为我直接用数组存不下,所以我们考虑先用一个节点表示一个区间,然后我们在要用到这个区间内的数时,再把这个节点分裂开.什么意思呢?比如我们想要找到第x个数,然后现在只有一个节点root,包括了1~n的范围,那么我们就把这个节点拆开,变成t[root].ch[0]保存1~x-1,t[root].ch[1]保存x+1~n,和一个我们需要的节点x.这样我们就把空间省了下来.
然后各个操作就是splay的基本操作了,将一个点提到第一位就是将它的中序遍历位置变到第一位,可以先将它旋到根,然后把后继旋到根下面,把它的左子树插到后继的左边。
这里就先不放代码了代码我还没有打,实在是太难打了.....。
时隔一年,远在致远星上的我想起了这道题(其实是看见同学也在写这题),于是回来把这题的代码给补了,康康之前写的博客,发现讲的东西实在是少,这里再补充一下:
- 平衡树的中序遍历结果表示了排名,节点上的值记录节点的编号,这样我们就可以通过平衡树建立节点在树中的编号到节点的存储编号/排名的映射.
- 因为中序遍历只能维护一个东西,所以要通过存储编号找节点需要用map来实现,也就是map[i]记录右端点为i的树中的节点编号,这样就可以从区间找到节点了.
再补充一下map使用lower_bound的方法:
在map中lower_bound相当与是对第一关键字进行二分,找到第一个大于等于第一关键字的元素,返回这个元素的迭代器,而这个迭代器所包含的值的类型是一个pair,其中它的第一关键字也就是第一个大于等于lower_bound查询的元素的值,第二关键字相当于map[第一关键字].
然后就是分离节点包含区间的过程中的各种细节了...看看代码吧.
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 2e5+5; 4 const int inf = 0x3f3f3f3f; 5 6 int n, m, cnt = 0, root = 0, lans = 0; 7 8 struct splay{ int ch[2], l, r, size, fa, val; }t[N]; 9 10 map <int, int> vis; 11 12 bool get(int x){ return x == t[t[x].fa].ch[1]; } 13 14 void up(int x){ t[x].size = t[t[x].ch[0]].size+t[t[x].ch[1]].size+t[x].r-t[x].l+1; } 15 16 int newnode(int val, int l, int r){ 17 t[++cnt].val = val, t[cnt].size = r-l+1, t[cnt].l = l, t[cnt].r = r; 18 return cnt; 19 } 20 21 void rotate(int x){ 22 int f = t[x].fa, gf = t[f].fa, d1 = get(x), d2 = get(f); 23 t[t[x].ch[d1^1]].fa = f, t[f].ch[d1] = t[x].ch[d1^1]; 24 t[x].ch[d1^1] = f, t[f].fa = x; 25 t[gf].ch[d2] = x, t[x].fa = gf; 26 up(f), up(x); 27 } 28 29 void splay(int x, int goal){ 30 while(t[x].fa != goal){ 31 int f = t[x].fa, gf = t[f].fa, d1 = get(x), d2 = get(f); 32 if(gf != goal){ 33 if(d1 == d2) rotate(f); 34 else rotate(x); 35 } 36 rotate(x); 37 } 38 if(goal == 0) root = x; 39 } 40 41 void insert(int now, int k){ 42 if(!k){ 43 splay(2, 0); int x = t[root].ch[1]; 44 while(t[x].ch[0]) x = t[x].ch[0]; 45 t[now].fa = x, t[x].ch[0] = now; 46 } else { 47 splay(3, 0); int x = t[root].ch[0]; 48 while(t[x].ch[1]) x = t[x].ch[1]; 49 t[now].fa = x, t[x].ch[1] = now; 50 } 51 splay(now, 0); 52 } 53 54 int kth(int k){ 55 int x = root, son; 56 while(1){ 57 if(k <= t[son = t[x].ch[0]].size) x = son; 58 else if(k > t[son].size+t[x].r-t[x].l+1) 59 k -= t[son].size+t[x].r-t[x].l+1, x = t[x].ch[1]; 60 else return x; 61 } 62 } 63 64 void delet(int k){ 65 int pre = kth(k-1), nex = kth(k+1), x; 66 splay(pre, 0), splay(nex, pre); x = t[nex].ch[0]; 67 t[nex].ch[0] = 0, splay(nex, 0); 68 } 69 70 void split(int x, int num){ 71 int son, ls, rs; 72 if(t[x].l == t[x].r) return; 73 if(t[x].l == num || t[x].r == num){ 74 if(t[x].l != num){ 75 son = newnode(t[x].l, t[x].l, num-1); 76 t[x].l = num, t[x].size = t[x].r-t[x].l+1, t[x].val = num; 77 t[son].ch[0] = t[x].ch[0], t[t[x].ch[0]].fa = son; 78 t[x].ch[0] = son, t[son].fa = x; up(son), up(x); 79 vis[num-1] = son, vis[num] = x; 80 } else { 81 son = newnode(num+1, num+1, t[x].r); 82 vis[t[x].r] = son, vis[num] = x; 83 t[x].r = num, t[x].size = t[x].r-t[x].l+1, t[x].val = num; 84 t[son].ch[1] = t[x].ch[1], t[t[x].ch[1]].fa = son; 85 t[x].ch[1] = son, t[son].fa = x; up(son), up(x); 86 } 87 } else { 88 ls = newnode(t[x].l, t[x].l, num-1); 89 rs = newnode(num+1, num+1, t[x].r); 90 vis[num-1] = ls, vis[t[x].r] = rs, vis[num] = x; 91 t[x].l = t[x].r = num, t[x].size = 1, t[x].val = num; 92 t[ls].ch[0] = t[x].ch[0], t[t[x].ch[0]].fa = ls; 93 t[x].ch[0] = ls, t[ls].fa = x; up(ls), up(x); 94 t[rs].ch[1] = t[x].ch[1], t[t[x].ch[1]].fa = rs; 95 t[x].ch[1] = rs, t[rs].fa = x; up(rs), up(x); 96 } 97 } 98 99 void init(){ 100 root = 1, cnt = 3, t[1].l = 1, t[1].r = n, t[1].val = n, vis[n] = 1; 101 t[1].size = n+2, t[1].ch[0] = 2, t[1].ch[1] = 3; 102 t[2].fa = t[3].fa = t[2].size = t[3].size = 1, t[2].val = -inf, t[3].val = inf; 103 } 104 105 int main(){ 106 ios::sync_with_stdio(false); 107 int opt, x, y, pos, now, k; cin >> n >> m; init(); 108 for(int i = 1; i <= m; i++){ 109 cin >> opt >> x, x -= lans; 110 if(opt == 1){ 111 cin >> y, y -= lans; 112 pos = (*vis.lower_bound(x)).first, now = vis[pos]; 113 splay(now, 0), split(now, x); 114 vis[x] = 0, vis[y] = now, t[now].val = y; 115 cout << (lans = t[t[now].ch[0]].size) << endl; 116 } 117 if(opt == 2 || opt == 3){ 118 pos = (*vis.lower_bound(x)).first, now = vis[pos]; 119 splay(now, 0), split(now, x); 120 k = t[t[now].ch[0]].size+1; 121 cout << (lans = k-1) << endl; 122 delet(k), insert(now, opt-2); 123 } 124 if(opt == 4){ 125 now = kth(x+1), splay(now, 0); 126 if(t[now].l != t[now].r) split(now, x-t[t[now].ch[0]].size+t[now].l); // 127 cout << (lans = t[now].val) << endl; 128 } 129 } 130 return 0; 131 }