维护书架
金牌导航 无旋式treap-1
题目大意
给出一个序列a,编号为1~n,让你做若干操作,操作有五种:
1.把第x个数放在最前面
2.把第x个数放在最后面
3.把第x个数和第x±1x\pm 1x±1个数交换
4.查询编号为i的数前面有多少个数
5.查询第i个数的编号
输入样例
10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2
输出样例
2
9
9
7
5
3
数据范围
3⩽n,m⩽8×104,1⩽ai⩽n3\leqslant n,m\leqslant 8\times 10^4,1\leqslant a_i\leqslant n3⩽n,m⩽8×104,1⩽ai⩽n
解题思路
用无旋式treap维护该数列
前三项就先把数字拆出来,然后再按要求放回去
对于操作四,在建点的时候寄一个标记,记下编号为x的数在树中的编号,然后搜一下就行了
对于操作五,就直接搜就行了(代码里是把书拆开,因为可以省去打一个函数)
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define sto_wyc_orz 666666
#define N 80080
using namespace std;
int n, m, x, y, w, t1, t2, t3, t4, rt, v[N], s[N], fa[N], ls[N], rs[N], pri[N], size[N];
string str;
void up(int x)
{size[x] = size[ls[x]] + size[rs[x]] + 1;return;
}
int newnode(int x)//建点
{s[++w] = x;pri[w] = rand();size[w] = 1;v[x] = w;return w;
}
int merge(int x, int y)//合并
{if (!x || !y) return x + y;if (pri[x] < pri[y]){rs[x] = merge(rs[x], y);fa[rs[x]] = x;up(x);return x;}else{ls[y] = merge(x, ls[y]);fa[ls[y]] = y;up(y);return y;}
}
void split(int x, int k, int &a, int &b, int faa, int fab)//拆分
{if (!x){a = b = 0;return;}if (k <= size[ls[x]]){fa[x] = fab;b = x;split(ls[x], k, a, ls[x], faa, x);}else{fa[x] = faa;a = x;split(rs[x], k - size[ls[x]] - 1, rs[x], b, x, fab);}up(x);
}
void insert(int x, int y)
{split(rt, x, t1, t2, 0, 0);rt = merge(t1, merge(newnode(y), t2));
}
int find(int x)
{int sum = size[ls[x]] + 1;while(x != rt){if (x == rs[fa[x]]) sum += size[ls[fa[x]]] + 1;x = fa[x];}return sum;
}
int main()
{srand(sto_wyc_orz);scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++i){ scanf("%d", &x);insert(i - 1, x);}while(m--){cin>>str;scanf("%d", &x);if (str == "Top"){x = find(v[x]);split(rt, x, t1, t3, 0, 0);split(t1, x - 1, t1, t2, 0, 0);//拆分再按要求合并rt = merge(t2, merge(t1, t3));}if (str == "Bottom"){x = find(v[x]);split(rt, x, t1, t3, 0, 0);split(t1, x - 1, t1, t2, 0, 0);rt = merge(t1, merge(t3, t2));}if (str == "Insert"){scanf("%d", &y);x = find(v[x]);if (y > 0){split(rt, x + 1, t3, t4, 0, 0);split(t3, x, t2, t3, 0, 0);split(t2, x - 1, t1, t2, 0, 0);rt = merge(merge(t1, t3), merge(t2, t4));}else if (y < 0){split(rt, x, t3, t4, 0, 0);split(t3, x - 1, t2, t3, 0, 0);split(t2, x - 2, t1, t2, 0, 0);rt = merge(merge(t1, t3), merge(t2, t4));}}if (str == "Ask"){printf("%d\n", find(v[x]) - 1);}if (str == "Query"){split(rt, x, t1, t2, 0, 0);y = t1;while(rs[y]) y = rs[y];//拆分后找最右边的,即第x个printf("%d\n", s[y]);rt = merge(t1, t2);}}return 0;
}