一开始拿到题,恩,还行吧,就是splay模拟一下。
看了一下数据,卧槽,n这么大,不过好在q比较小,所以需要离散化。
线段树的离散化是把数字排序去重,每个数字对应在数组中的位置。
splay的离散化要是这么写估计得挂。
splay的离散化:将要操作的点加到数组中排序、去重,按顺序,每个点加入,并且相连两个点之间的区间算作一个点加入。
也就是,splay的每个点实际上维护了一段区间。 到时候二分一下,就可以找到每个数字对应在哪个点的区间内。
题意:n个点,q次操作。
Top x,把x这个数取出来放到最前面。 存一下每个splay点的地址,直接找一下,把这个点(离散这个点保证区间长度为1)旋到根,删掉,再在最左边加入。
Query x,询问x是排名第几的数 把x所在的区间对应的点放到根(离散这个点保证区间长度为1),root左区间长+1就是答案。
Rank x,询问排名第k的是哪一个数 按照找排名第k那样做,把排名为第k的区间找到,旋到根,k-左子树-1就是它在root的区间内的排名。
首先,照样来上splay的版(rotate,splay 还有一个insert,我比较懒,不想用build)
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];
u->ch[d^1]=f;
f->f=u;
if(ff!=null)ff->ch[dd]=u;
u->f=ff;
f->rs();
u->rs();
}
void splay(node *u,node *p)
{
while(u->f!=p)
{
node *f=u->f;
node *ff=f->f;
if(ff==p)
{
rotate(u);
break;
}
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;
u->rs();
}
void insert(node *&u,node *&fa,int key)
{
if(u==null)
{
u=newnode(key);
u->f=fa;
splay(u,null);
return ;
}
insert(u->ch[1],u,key);
u->rs();
}
然后对于Top:
我们先找到x对应区间标号,二分:
int bin(int x)
{
int l=1,r=tot;
while(l<=r)
{
int mid=l+r>>1;
if(s[mid]>x)r=mid-1;
else if(e[mid]<x)l=mid+1;
else return mid;
}
return l;
}
然后,把标号为bin(x)旋到根(存过地址)
然后,DEL ROOT()
void Del()
{
node *u=root;
if(root->ch[1]!=null)
{
root=root->ch[1];
select(1);//(select是从root找排名第k的点并旋到根)
if(u->ch[0]!=null)u->ch[0]->f=root;
root->ch[0]=u->ch[0];
}
else
{
root=root->ch[0];
}
root->f=null;
if(root==null)return ;
root->rs();
}
然后在最左边重新插入:
void rin(node *&u,node *&fa,int key)
{
if(u==null)
{
u=newnode(key);
u->f=fa;
return ;
}
rin(u->ch[0],u,key);
u->rs();
}
把x对应的区间的点找到(二分+地址),旋到根,直接左子树+1
RANK x://询问排第x的是谁
利用select函数,查找排名为k的对应区间,旋到根。
x-root->ch[0]-sz-1是在根的区间中对应的位置。
void select(int k)//查询第k个的位置并将其移到根
{
node *u=root;
while(1)
{
if(k<=u->ch[0]->sz+u->num&&k>u->ch[0]->sz)break;
if(k<=u->ch[0]->sz)u=u->ch[0];
else
{
k-=u->ch[0]->sz+u->num;
u=u->ch[1];
}
}
splay(u,null);
}
全代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int maxn=100000+15;
struct node
{
int key,sz,num;//key离散后的点,sz大小,num维护的单点区间长
node *f;
node *ch[2];
node(){}
node (int a,int b)
{
key=a;
sz=num=b;
}
void rs()
{
sz=ch[0]->sz+ch[1]->sz+num;
}
}S[maxn<<2],*pos[maxn],*root,*null;
int cnt,ncnt,tot;
int det[maxn];
int s[maxn],e[maxn];
struct Ans
{
int k,x;
}ans[maxn];
int n,q;
void clear()
{
null=new node(-1,0);
root=null;
ncnt=0;
}
node *newnode(int x)
{
node *u=&S[++ncnt];
u->key=x;
pos[x]=u;
u->sz=u->num=e[x]-s[x]+1;
u->f=u->ch[0]=u->ch[1]=null;
return u;
}
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];
u->ch[d^1]=f;
f->f=u;
if(ff!=null)ff->ch[dd]=u;
u->f=ff;
f->rs();
u->rs();
}
void splay(node *u,node *p)
{
while(u->f!=p)
{
node *f=u->f;
node *ff=f->f;
if(ff==p)
{
rotate(u);
break;
}
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;
u->rs();
}
int bin(int x)
{
int l=1,r=tot;
while(l<=r)
{
int mid=l+r>>1;
if(s[mid]>x)r=mid-1;
else if(e[mid]<x)l=mid+1;
else return mid;
}
return l;
}
void select(int k)//查询第k个的位置并将其移到根
{
node *u=root;
while(1)
{
if(k<=u->ch[0]->sz+u->num&&k>u->ch[0]->sz)break;
if(k<=u->ch[0]->sz)u=u->ch[0];
else
{
k-=u->ch[0]->sz+u->num;
u=u->ch[1];
}
}
splay(u,null);
}
void Del()
{
node *u=root;
if(root->ch[1]!=null)
{
root=root->ch[1];
select(1);
if(u->ch[0]!=null)u->ch[0]->f=root;
root->ch[0]=u->ch[0];
}
else
{
root=root->ch[0];
}
root->f=null;
if(root==null)return ;
root->rs();
}
void find(int x)
{
node *u=pos[x];
splay(u,null);
}
void rin(node *&u,node *&fa,int key)
{
if(u==null)
{
u=newnode(key);
u->f=fa;
return ;
}
rin(u->ch[0],u,key);
u->rs();
}
void insert(node *&u,node *&fa,int key)
{
if(u==null)
{
u=newnode(key);
u->f=fa;
splay(u,null);
return ;
}
insert(u->ch[1],u,key);
u->rs();
}void dfs(node *u)
{
if(u->ch[0]!=null)dfs(u->ch[0]);
cout<<u->key<<" "<<u->sz<<" "<<u->num<<endl;
if(u->ch[1]!=null)dfs(u->ch[1]);
}
void Top(int x)
{
int k=bin(x);//k是第几个点
find(k);
Del();
rin(root,null,k);
find(k);
}
int getrank(int x)//第几个的排名
{
find(bin(x));
return root->ch[0]->sz+1;
}
int getKth(int x)//排名第x是谁
{
select(x);//查询排名第几所在的点(区间)
return s[root->key]+(x-root->ch[0]->sz)-1;
}
char ss[20];
int main()
{
int T;
scanf("%d",&T);
int cas=0;
while(T--)
{
printf("Case %d:\n",++cas);
scanf("%d%d",&n,&q);
cnt=0;
clear();
det[++cnt]=0;
for(int i=1;i<=q;i++)
{
scanf("%s%d",ss,&ans[i].x);
if(ss[0]=='T')ans[i].k=1;
if(ss[0]=='Q')ans[i].k=2;
if(ss[0]=='R')ans[i].k=3;
if(ans[i].k!=3)det[++cnt]=ans[i].x;
}
det[++cnt]=n;
sort(det+1,det+cnt+1);
int m=unique(det+1,det+cnt+1)-det-1;
tot=0;
for(int i=2;i<=m;i++)
{
if(det[i]-det[i-1]>1)
{
tot++;
s[tot]=det[i-1]+1;
e[tot]=det[i]-1;
}
tot++;
s[tot]=e[tot]=det[i];
}
for(int i=1;i<=tot;i++)insert(root,null,i);
for(int i=1;i<=q;i++)
{
if(ans[i].k==1)
{
Top(ans[i].x);
}
else if(ans[i].k==2)
{
printf("%d\n",getrank(ans[i].x));
}
else
{
printf("%d\n",getKth(ans[i].x));
}
}
}
return 0;
}