http://www.lydsy.com/JudgeOnline/problem.php?id=3594
(貌似比维护数列更恶心QAQ,虽然我只是看了一眼不想写)
方法:splay+双map
这道题真够恶心,它坑了我一上午~~还是下午来的时候调出来的。
首先看到数据范围n<=10^8就知道不可以每个点都搞出来,需要离散。m<=10^5,开个300000的内存池就好了。
然后我们需要离散,也就是每个点保存一段区间。
然后首先是[l,r]
每次操作之后把[l,r]拆成[l,a-1],[a,a],[a+1,r]三个区间,并且把a映射.
我们需要两个map.
第一个id[x]表示编号为x的在splay中r的值,pos[r]表示splay中r对应的编号。
初始为0,那么就映射x(或者修改)。
(所有的操作-a得到本来的操作)
详细操作:
需要ll,rr维护最左边是多少,最右边是多少
操作1: 把id[x]找到,如果没有返回x,t=id[x]然后修改id[y]=t,id[x]=0. 然后id[x]被旋到根,拆成3段。&&记录pos[t]=y;
操作2: 把id[x]找到,如果没有返回x,t=id[x],然后拆成三段,删掉根[t,t],在左边新建ll--,把[ll,ll]插入最左边。此时id[x]=ll pos[ll]=x
操作3: 同操作2,不过删掉根[t,t]后,在最右边新建rr++,把[rr,rr]加到最右边。id[x]=rr,pos[rr]=x
操作4: 把x所在位置旋到根,l!=r拆成三段读取位置,并且映射。否则,读取pos[r](有可能为空,我之前没考虑,以为没有拆就不可能单独成为一个点,没考虑到如果它左右两端都被拆了,它也算是一个点了,这个时候没有映射,就读取r就好了。)
总结,利用双map映射编号和splay中的位置。 每次询问使用用find找x所在区间(splay维护的关键词就是r,可以保证能找到) 最后排名写一个select利用size找一下。 每次要旋到根。
我用指针写还跑得这么慢(评测机对STL不友好吧~~)
(吐槽:map真的很慢,要不再写一个splay; 额,算了~~纯粹蛋疼~)
再吐槽,我写newnode的时候手残没返回,本地测试所有数据都过了,交cena RE,调了很久才发现。
&& 写rotate的时候,盘dd=f==ff->ch[1]时,前面忘写dd=了,就GG了。
跑2s多的写的treap吧QAQ.
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
const int maxn=300000+20;
using namespace std;
map<int,int>id;
map<int,int>pos;
int read()
{
int res=0;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())res=res*10+ch-'0';
return res;
}
struct node
{
node *f;
node *ch[2];
int sz;
int l,r;
}S[maxn],*null,*root,Tnull;
int ncnt=0;
int a,n,m;
void init(node *u)
{
u->f=u->ch[0]=u->ch[1]=null;
u->sz=0;
u->l=u->r=0;
}
node *newnode(int l,int r)
{
node *u=&S[++ncnt];
u->l=l;
u->r=r;
u->f=null;
u->ch[0]=u->ch[1]=null;
u->sz=r-l+1;
return u;
}
void pushup(node *u)
{
u->sz=u->ch[0]->sz+u->ch[1]->sz+u->r-u->l+1;
}
void rotate(node *u)
{
node *f=u->f;
if(f==null)return ;
node *ff=f->f;
int d=u==f->ch[1];
int dd=0;
if(ff!=null)dd=f==ff->ch[1];
if(u->ch[d^1]!=null)u->ch[d^1]->f=f;
f->ch[d]=u->ch[d^1];
f->f=u;
u->ch[d^1]=f;
if(ff!=null)ff->ch[dd]=u;
u->f=ff;
pushup(f);
pushup(u);
}
void splay(node *u,node *p)
{
while(u->f!=p)
{
node *f=u->f;
node *ff=f->f;
if(ff==p)
{
rotate(u);
break;
}
else
{
int d=u==f->ch[1];
int dd=f==ff->ch[1];
if(d==dd)rotate(f);
else rotate(u);
rotate(u);
}
}
if(p==null)root=u;
pushup(u);
}
void insert(int l,int r)
{
if(root==null)
{
root=newnode(l,r);
return ;
}
node *u=root;
node *y;
while(1)
{
u->sz+=r-l+1;
if(u->ch[1]!=null)u=u->ch[1];
else
{
y=newnode(l,r);
y->f=u;
u->ch[1]=y;
break;
}
}
splay(y,null);
}
void find(int x)
{
node *u=root;
while(1)
{
if(x>=u->l&&x<=u->r)
{
splay(u,null);
return ;
}
if(x<u->l)u=u->ch[0];
else u=u->ch[1];
}
}
void select(int x)
{
node *u=root;
while(1)
{
int d=u->r-u->l+1;
if(x>u->ch[0]->sz&&x<=u->ch[0]->sz+d)
{
splay(u,null);
return ;
}
else if(x<=u->ch[0]->sz)u=u->ch[0];
else
{
x-=u->ch[0]->sz+d;
u=u->ch[1];
}
}
}
void split(int t,node *u)
{
int l=u->l,r=u->r;
if(l==r)return ;
node *x=null,*y=null;
u->l=u->r=t;
if(l<=t-1)x=newnode(l,t-1);
if(t+1<=r)y=newnode(t+1,r);
if(x!=null)
{
x->ch[0]=u->ch[0];
if(u->ch[0]!=null)u->ch[0]->f=x;
x->f=u;
u->ch[0]=x;
pushup(x);
}
if(y!=null)
{
y->ch[1]=u->ch[1];
if(u->ch[1]!=null)u->ch[1]->f=y;
y->f=u;
u->ch[1]=y;
pushup(y);
}
pushup(u);
}
void del()
{
if(root->ch[1]==null)
{
root=root->ch[0];
root->f=null;
pushup(root);
}
else
{
node *u=root->ch[1];
while(u->ch[0]!=null)u=u->ch[0];
splay(u,root);
root->ch[0]->f=u;
u->ch[0]=root->ch[0];
root=u;
root->f=null;
pushup(root);
}
}
int main()
{
null=&Tnull;
ncnt=0;
init(null);
root=null;
a=0;
n=read(),m=read();
int ll=0,rr=n;
insert(1,n);
int op;
for(int i=1;i<=m;i++)
{
op=read();
if(op==1)//找到这个点x,把它旋到根分解成3个,然后找排名
{
int x=read(),y=read();
x-=a;
y-=a;
int t=id[x];
if(!t)t=x;
find(t);
split(t,root);
a=root->ch[0]->sz+1;
id[y]=t;
id[x]=0;
pos[t]=y;
}
else if(op==2)
{
int x=read();
x-=a;
int t=id[x];
if(!t)t=x;
find(t);
split(t,root);
a=root->ch[0]->sz+1;
del();
--ll;
id[x]=ll;
pos[ll]=x;
node *u=root;
while(u->ch[0]!=null)u=u->ch[0];
node *y=newnode(ll,ll);
u->ch[0]=y;
y->f=u;
splay(y,null);
}
else if(op==3)
{
int x=read();
x-=a;
int t=id[x];
if(!t)t=x;
find(t);
split(t,root);
a=root->ch[0]->sz+1;
del();
++rr;
id[x]=rr;
pos[rr]=x;
node *u=root;
while(u->ch[1]!=null)u=u->ch[1];
node *y=newnode(rr,rr);
u->ch[1]=y;
y->f=u;
splay(y,null);
}
else
{
int x=read();
x-=a;
select(x);
if(root->l!=root->r)
{
a=x-root->ch[0]->sz-1+root->l;
split(a,root);
id[a]=a;
pos[a]=a;
}
else
{
a=pos[root->l];
if(!a)a=root->l;
}
}
printf("%d\n",a);
}
return 0;
}