题面
Bzoj3595
解析
wys讲到用Splay, 但我又一次写成了Spaly
考虑到n的范围巨大而m的范围是正常的1e5, 显然要动态开点,一个点代表一个区间。但这道题只用一棵平衡树可能不太好做,于是有dalao就写了两棵平衡树, 显然我这种一棵平衡树都要写挂的人是不可能去完成两棵平衡树的,于是可以用map代替其中一棵树。其中map第一关键字为区间的右端点,第二关键字为节点编号,要分裂点的时候先查询分裂的节点, 用lower_bound可以在log的时间内查到, 再分裂节点就行, 显然操作1、2、3需要分裂节点。
对于操作2,当然先是找到节点,然后旋转到根,查询前驱和后继,分情况讨论删除根,再把序列rk1转到根节点, 把删除的节点挂在左二子上就行。操作3类似,删除根及其之前的操作都和操作2一样,只不过操作3要把rk last转到根节点,把删除的节点挂在右儿子上就行
细节
分裂节点时分成了[l, val - 1], [val, val] [val + 1, r]三个区间,要注意判断[l, val - 1], [val + 1, r]两个区间是否存在
0号节点的右儿子要赋成root, 删除节点时要更新(这个我调了2个小时)
代码:


#include<bits/stdc++.h> using namespace std; const int maxn = 500005;template<class T> void read(T &re) {re=0;T sign=1;char tmp;while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0';while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');re*=sign; }int n, m, res, root, tot; map<int,int> mp;struct splay_tree{int l, r, s[2], fa, siz; }tr[maxn];int Newnode(int l, int r, int f) {int ret = ++tot;tr[ret].l = l;tr[ret].r = r;tr[ret].fa = f;tr[ret].siz = r - l + 1;return ret; }void update(int x) {int ls = tr[x].s[0], rs = tr[x].s[1];tr[x].siz = tr[ls].siz + tr[rs].siz + tr[x].r - tr[x].l + 1; }void Rotate(int x) {int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];tr[y].s[k] = son;tr[son].fa = y;tr[x].s[k^1] = y;tr[y].fa = x;tr[z].s[w] = x;tr[x].fa = z;update(y);update(x); }void Splay(int x, int to) {while(tr[x].fa != to){int y = tr[x].fa, z = tr[y].fa;if(z == to){Rotate(x);break;}Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y); Rotate(x);}if(!to)root = x; }int Find(int x) {int now = root;while(1){int ls = tr[now].s[0], rs = tr[now].s[1], sum = tr[ls].siz + tr[now].r - tr[now].l + 1;if(x > tr[ls].siz && x <= sum){x -= tr[ls].siz;break;}if(x <= tr[ls].siz) now = ls;else x -= sum, now = rs;}return tr[now].l + x - 1; }void Split(int x, int val) {int ls, rs, L = tr[x].l, R = tr[x].r;if(L == R)return ;if(L == val){rs = ++tot;mp[R] = rs;mp[val] = x;tr[rs].s[1] = tr[x].s[1];tr[tr[rs].s[1]].fa = rs;tr[x].s[1] = rs;tr[rs].fa = x;tr[rs].l = L + 1;tr[rs].r = R;tr[x].r = L;update(rs);update(x);}else if(R == val){ls = ++tot;mp[R - 1] = ls;mp[val] = x;tr[ls].s[0] = tr[x].s[0];tr[tr[x].s[0]].fa = ls;tr[x].s[0] = ls;tr[ls].fa = x;tr[ls].l = L;tr[ls].r = R - 1;tr[x].l = R;update(ls);update(x);}else{ls = ++tot; rs = ++tot; mp[val] = x;mp[val-1] = ls;mp[R] = rs;tr[ls].s[0] = tr[x].s[0];tr[rs].s[1] = tr[x].s[1];tr[tr[x].s[0]].fa = ls;tr[tr[x].s[1]].fa = rs;tr[x].s[0] = ls;tr[x].s[1] = rs;tr[x].l = tr[x].r = val;tr[ls].fa = tr[rs].fa = x;tr[ls].l = L;tr[ls].r = val - 1;tr[rs].l = val + 1;tr[rs].r = R;update(ls);update(rs);update(x);}Splay(x, 0); }int Query(int x) {Splay(x, 0);return tr[x].siz - tr[tr[x].s[1]].siz; } int timer; void Del(int x) {int pre = tr[x].s[0], las = tr[x].s[1];while(tr[pre].s[1]) pre = tr[pre].s[1];while(tr[las].s[0]) las = tr[las].s[0];if(!pre && !las) root = 0;else if(!pre){Splay(las, root);root = las;tr[root].fa = 0;tr[0].s[1] = root;tr[x].s[0] = tr[x].s[1] = 0;tr[x].siz = 1;}else if(!las){Splay(pre, root);root = pre;tr[root].fa = 0;tr[0].s[1] = root;tr[x].s[0] = tr[x].s[1] = 0;tr[x].siz = 1;}else {Splay(pre, 0);Splay(las, root);tr[las].s[0] = tr[x].fa = 0;tr[x].siz = 1;update(las);update(pre);} }void Insert_front(int x) {if(!root){root = x;return ;}int lef = root;while(tr[lef].s[0]) lef = tr[lef].s[0];Splay(lef, 0);tr[root].s[0] = x;tr[x].fa = root;update(root); }void Insert_back(int x) {if(!root){root = x;return ;}int rig = root;while(tr[rig].s[1])rig = tr[rig].s[1];Splay(rig, 0);tr[root].s[1] = x;tr[x].fa = root;update(x);update(root); }int main() {read(n);read(m);mp[n] = root = Newnode(1, n, 0);tr[0].s[1] = root;for(int i = 1; i <= m; ++i){timer ++;int opt, x, y;read(opt);read(x);if(opt == 1){read(y);x -= res;y -= res;int z = mp.lower_bound(x) -> second;Split(z, x);res = Query(z);tr[z].l = tr[z].r = y;mp[y] = z;}else if(opt == 2){x -= res;int y = mp.lower_bound(x) -> second;Split(y, x);res = Query(y);Del(y);Insert_front(y);}else if(opt == 3){x -= res;int y = mp.lower_bound(x) -> second;Split(y, x);res = Query(y);Del(y);Insert_back(y);}else{x -= res;res = Find(x);}printf("%d\n", res);}return 0; }