【BZOJ3678】wangxz与OJ Splay
【BZOJ3678】wangxz与OJ
Description
某天,wangxz神犇来到了一个信息学在线评测系统(Online Judge)。由于他是一位哲♂学的神犇,所以他不打算做题。他发现这些题
目呈线性排列,被标记为1~n号,每道题都有一个难度值(可以<=0)。他决定与这些题目玩♂耍。
1、他可以在某个位置插♂入一些难度值特定的题目。
2、他可以吃♂掉(删除)一段题目。
3、他可以查询某个位置的题目的难度值。
维护一个初始有n个元素的序列(标记为1~n号元素),支持以下操作:
0 p a b (0<=p<=当前序列元素个数) (a<=b) 在p位置和p+1位置之间插入整数:a,a+1,a+2,...,b-1,b。若p为0,插在序列最前面;
1 a b (1<=a<=b<=当前序列元素个数) 删除a,a+1,a+2,...,b-1,b位置的元素;
2 p (1<=p<=当前序列元素个数) 查询p位置的元素。
Input
输入第一行包括两个正整数n(1<=n<=20000),m(1<=m<=20000),代表初始序列元素个数和操作个数。
接下来n个整数,为初始序列元素。
接下来m行,每行第一个为整数sym,
若sym=0,接下来有一个非负整数p,两个整数a,b;
若sym=1,接下来有两个正整数a,b;
若sym=2,接下来有一个正整数p;
p、x、y的含义及范围见题目描述。
在任何情况下,保证序列中的元素总数不超过100000。
保证题目涉及的所有数在int内。
Output
对每个sym=2,输出一行,包括一个整数,代表询问位置的元素。
Sample Input
1 2 3 4 5
0 2 1 4
1 3 8
2 2
Sample Output
题解:容易想到用Splay,我们的Splay的每个节点处维护的不是一个点,而是连续的一段数[a,b]。我们需要实现一个split操作:如果我们想将c和c+1分开,那么我们先找到c所在的节点,将它的后继提上来,并在二者之间新建一个点,将当前节点变成[a,c],并将新点变成[c+1,b]即可。特别地,如果c==b,则不用操作。
其余的操作就很容易了。
#include <cstdio> #include <iostream> #include <cstring> using namespace std; struct node { int ch[2],a,b,fa,siz; }s[200010]; int n,m,tot,rt; inline void pushup(int x) { s[x].siz=s[s[x].ch[0]].siz+s[s[x].ch[1]].siz+s[x].b-s[x].a+1; } int build(int l,int r) { if(l>r) return 0; int x=(l+r)>>1; s[x].ch[0]=build(l,x-1),s[x].ch[1]=build(x+1,r); if(s[x].ch[0]) s[s[x].ch[0]].fa=x; if(s[x].ch[1]) s[s[x].ch[1]].fa=x; pushup(x); return x; } inline void rotate(int x,int &k) { int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]); if(z) s[z].ch[y==s[z].ch[1]]=x; else if(y==k) k=x; s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1]; if(s[x].ch[d^1]) s[s[x].ch[d^1]].fa=y; s[x].ch[d^1]=y; pushup(y),pushup(x); } inline void splay(int x,int &k) { while(x!=k) { int y=s[x].fa,z=s[y].fa; if(y!=k) { if((x==s[y].ch[0])^(y==s[z].ch[0])) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int find(int x,int y) { if(!x) return 0; if(y>s[s[x].ch[0]].siz&&y<=s[s[x].ch[0]].siz+s[x].b-s[x].a+1) return x; if(s[s[x].ch[0]].siz>=y) return find(s[x].ch[0],y); return find(s[x].ch[1],y-s[s[x].ch[0]].siz-s[x].b+s[x].a-1); } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); return ret*f; } inline void split(int y) { int x=find(rt,y+1); splay(x,rt),splay(find(rt,s[s[x].ch[0]].siz+s[x].b-s[x].a+2),s[x].ch[1]); if(s[s[x].ch[0]].siz+s[x].b-s[x].a==y) return ; int z=++tot; s[z].b=s[x].b,s[x].b=s[x].a+y-s[s[x].ch[0]].siz,s[z].a=s[x].b+1; s[z].fa=s[x].ch[1],s[s[x].ch[1]].ch[0]=z; pushup(z),pushup(s[x].ch[1]),pushup(x); rotate(z,s[x].ch[1]); } int main() { n=rd(),m=rd(); int i,x,y,a,b,op; for(i=1;i<=n;i++) s[i+1].a=s[i+1].b=rd(); rt=build(1,n+2),tot=n+2; for(i=1;i<=m;i++) { op=rd(); if(op==0) { a=rd(),split(a); x=++tot,s[x].a=rd(),s[x].b=rd(),s[x].fa=s[rt].ch[1],s[s[rt].ch[1]].ch[0]=x; pushup(x),pushup(s[rt].ch[1]),pushup(rt); } if(op==1) { a=rd(),b=rd(),split(a-1),split(b); x=find(rt,a),splay(x,rt),y=find(rt,b+2),splay(y,s[x].ch[1]); s[y].ch[0]=0; pushup(y),pushup(x); } if(op==2) { a=rd(),x=find(rt,a+1),splay(x,rt); printf("%d\n",a-s[s[x].ch[0]].siz+s[x].a); } } return 0; }//5 3 1 2 3 4 5 0 2 1 4 1 3 8 2 2
| 欢迎来原网站坐坐! >原文链接<