【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

5 3
1 2 3 4 5
0 2 1 4
1 3 8
2 2

Sample Output

2

题解:容易想到用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

 

posted @ 2017-11-26 12:11  CQzhangyu  阅读(298)  评论(0编辑  收藏  举报