【3595: [Scoi2014]方伯伯的Oj】区间拆分splay
少有的一遍写完过完样例就A的题,本身并不难,但这道题的思想还是很有用的。
BZOJ3595
3595: [Scoi2014]方伯伯的Oj
Time Limit: 6 Sec Memory Limit: 256 MB Submit: 772 Solved: 306 [Submit][Status][Discuss]Description
方伯伯正在做他的Oj。现在他在处理Oj上的用户排名问题。
Oj上注册了n个用户,编号为1~”,一开始他们按照编号排名。方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号:
1.操作格式为1 x y,意味着将编号为z的用户编号改为V,而排名不变,执行完该操作后需要输出该用户在队列中的位置,数据保证x必然出现在队列中,同时1,是一个当前不在排名中的编号。
2.操作格式为2 x,意味着将编号为x的用户的排名提升到第一位,执行完该操作后需要输出执行该操作前编号为z用户的排名。
3.操作格式为3 x,意味着将编号为z的用户的排名降到最后一位,执行完该操作后需要输出执行该操作前编号为z用户的排名。
4.操作格式为4 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
现在你截获丁方伯伯的所有操作,希望你能给出结果。
Input
输入的第1行包含2个用空格分隔的整数n和m,表示初始用户数和操作数。
此后有m行,每行是一个询问,询问格式如上所示。
Output
输出包含m行。每行包含一个整数,其中第i行的整数表示第i个操作的输出。
Sample Input
10 10
1 2 11
3 13
25
37
28
2 10
2 11
3 14
2 18
4 9
Sample Output
2
2
2
4
3
5
5
7
8
11
HINT
对于 100% 的数据,1 ≤ n ≤ 10^8,1 ≤ m ≤ 10^5
输入保证对于所有的操作 1,2,3,x 必然已经出现在队列中,同时对于所有操作 1,1 ≤ y ≤ 2 × 10^8,并且
y 没有出现在队列中。
对于所有操作 4,保证 1 ≤ k ≤ n。
乍眼看,splay板题?
欸不对怎么n这么大?
其实我们完全splay维护一个区间,记录L,R。同时我们利用两个map互相映射方便我们操作,之后初始一个splay结点囊括[1,n],之后只要从中间分裂,如[1,x-1][x][x+1,n]这样就可以了(当然具体怎样要细加分析)。
贼丑的code
#include<stdio.h> #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<map> #define zig(x) zigzag(x,1) #define zag(x) zigzag(x,2) using namespace std; const int maxn = 500005; int n,m; map<int,int>ma1; // origin id --> splay id (Ldd) map<int,int>ma2; // splay id --> origin id int ls[maxn],rs[maxn],fa[maxn],siz[maxn],L[maxn],R[maxn],rt,tot; void upd(int x) { siz[x] = siz[ls[x]] + siz[rs[x]] + R[x] - L[x] + 1; } void zigzag(int x,int kd) { int y,z; y = fa[x]; z = fa[y]; if(z) { if(ls[z]==y) ls[z] = x; else rs[z] = x; } fa[x] = z; fa[y] = x; if(kd==1) { ls[y] = rs[x]; fa[ls[y]] = y; rs[x] = y; } else{ rs[y] = ls[x]; fa[rs[y]] = y; ls[x] = y; } upd(y); upd(x); } void splay(int x){ int y , z; while(fa[x]) { y = fa[x]; z = fa[y]; if(!z) { if(ls[y]==x) zig(x); else zag(x); } else { if(ls[z]==y) { if(ls[y]==x) zig(y),zig(x); else zag(x),zig(x); }else { if(rs[y]==x) zag(y),zag(x); else zig(x),zag(x); } } } rt = x; } int split(int spb,int x) { splay(spb); if(x==L[spb]) { ++tot; ls[tot] = ls[spb]; ls[spb] = tot; fa[ls[tot]] = tot; fa[tot] = spb; L[spb]++; L[tot] = R[tot] = x; ma1[x] = tot; ma2[tot] = x; ma1[x+1] = spb; ma2[spb] = x+1; upd(tot); upd(spb); return tot; } else if(x==R[spb]) { ++tot; rs[tot] = rs[spb]; rs[spb] = tot; fa[rs[tot]] = tot; fa[tot] = spb; R[spb]--; R[tot] = L[tot] = x; ma1[x] = tot; ma2[tot] = x; ma1[L[spb]] = spb; ma2[spb] = L[spb]; upd(tot); upd(spb); return tot; } int lo = ++tot; ls[lo] = ls[spb]; ls[spb] = lo; fa[lo] = spb; fa[ls[lo]] = lo; L[lo] = L[spb]; L[spb] = x; R[lo] = x-1; ma1[L[lo]] = lo; ma2[lo] = L[lo]; ma1[x] = spb; ma2[spb] = x; int ro = ++tot; rs[ro] = rs[spb]; rs[spb] = ro; fa[ro] = spb; fa[rs[ro]] = ro; R[ro] = R[spb]; R[spb] = x; L[ro] = x+1; ma1[L[ro]] = ro; ma2[ro] = L[ro]; upd(lo); upd(ro); upd(spb); return spb; } int ggg(int x){ map<int,int>::iterator it; it = ma1.upper_bound(x); it--; int spb = it->second; if(R[spb]==L[spb]) return spb; else return split(spb,x); } int getmax(int x) { while(rs[x]) x = rs[x]; return x; } int getk(int k) { int p = rt; while(p) { if( siz[ls[p]] + 1 <= k && k <= siz[ls[p]] + (R[p]-L[p]+1) ) break; else { if(siz[ls[p]]>=k) p = ls[p]; else { k -= siz[ls[p]] + (R[p]-L[p]+1); p = rs[p]; } } } return p; } void insfi(int x) { int p = rt; while(p) { siz[p] += (R[x]-L[x]+1); if(ls[p]) p = ls[p]; else { ls[p] = x; fa[x] = p; upd(p); break; } } splay(x); } void insla(int x) { int p = rt; while(p) { siz[p] += (R[x]-L[x]+1); if(rs[p]) p = rs[p]; else { rs[p] = x; fa[x] = p; upd(p); break; } } splay(x); } void cut(int p) { splay(p); int lo = ls[p]; int ro = rs[p]; fa[lo] = fa[ro] = ls[p] = rs[p] = 0; upd(p); if(!lo) { rt = ro; return; } lo = getmax(lo); splay(lo); fa[ro] = lo; rs[lo] = ro; upd(lo); return; } int main() { scanf("%d%d",&n,&m); rt = ++tot; L[tot] = 1; R[tot] = n; ma1[1] = 1; ma2[1] = 1; siz[tot] = n; int lastans = 0; for(int i=1;i<=m;i++) { int op; scanf("%d",&op); if(op==1) { int x,y; scanf("%d%d",&x,&y); x -= lastans; y -= lastans; int spb = ggg(x); ma1[x] = 0; ma2[spb] = y; ma1[y] = spb; splay(spb); lastans = siz[ls[spb]] + 1; printf("%d\n",lastans); } else if(op==2) { int x; scanf("%d",&x); x -= lastans; int spb = ggg(x); splay(spb); lastans = siz[ls[spb]] + 1; printf("%d\n",lastans); cut(spb); insfi(spb); } else if(op==3) { int x; scanf("%d",&x); x -= lastans; int spb = ggg(x); splay(spb); lastans = siz[ls[spb]] + 1; printf("%d\n",lastans); cut(spb); insla(spb); }else { int k; scanf("%d",&k); k -= lastans; int spb = getk(k); splay(spb); k-=siz[ls[spb]]; lastans = ma2[spb]+ k - 1; printf("%d\n",lastans); } } }