题解 P3285 【[SCOI2014]方伯伯的OJ】
考虑将所有用户分成3类
原本的1->n,被提前的,被拉后的
对2,3类都开个平衡树
记录每个用户属于哪一类,以及对应的平衡树中的节点编号
平衡树也反过来记录节点对应的用户编号
这样如果在2,3类查询rank,k大就ok了
如果在1类查询rank,k大
因为节点个数是O(n)的,所以不能直接维护
所以对不在1类的点用平衡树维护
O(mlogm)
在实现中,2,3类我直接用线段树维护了
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=l;i<=r;++i)
int lastans;
#define gc (c=getchar())
int read()
{
char c;
while(gc<'0');
int x=c-'0';
while(gc>='0')x=x*10+c-'0';
return x;
}
int r()
{
#ifdef ONLINE_JUDGE
return read()-lastans;
#else
return read();
#endif
}
const int N=1e5+5;
int n,m,d;
struct SET
{
int a[N*3],id[N],n;
int insert(int _id)
{
++n;
id[n]=_id;
int i=n+d;
a[i]=1;
while(i>>=1)++a[i];
return n;
}
void del(int i)
{
i+=d;
a[i]=0;
while(i>>=1)--a[i];
}
int rank(int i)
{
i+=d;
int ans=a[i];
while(i)
{
if(i&1)ans+=a[i-1];
i>>=1;
}
return ans;
}
int find_by_rank(int x)
{
int i=1;
while(i<=d)
{
if(x<=a[i*2])i*=2;
else
{
x-=a[i*2];i=i*2+1;
}
}
return id[i-d];
}
};
SET pre,suf;
struct SPLAY
{
#define cl(x) c[x][0]
#define cr(x) c[x][1]
int fa[N],c[N][2],sz[N];
int v[N],n,rt;
int rank(int x)
{
int ans=x;
int i=rt;
while(i)
if(v[i]>x)i=cl(i);
else
{
ans-=sz[cl(i)]+1;
i=cr(i);
}
return ans;
}
void sc(int y,int x,bool d)
{
fa[x]=y;c[y][d]=x;
}
bool get(int x)
{
return x==c[fa[x]][1];
}
void up(int x)
{
sz[x]=sz[cl(x)]+sz[cr(x)]+1;
}
void rot(int x)
{
int y=fa[x];bool d=get(x);
if(y==rt)fa[rt=x]=0;
else sc(fa[y],x,get(y));
sc(y,c[x][!d],d);
sc(x,y,!d);
up(y);
}
void splay(int x,int to=0)
{
int y;
while(y=fa[x],y!=to)
{
if(fa[y]==to){rot(x);break;}
rot(get(x)==get(y)?y:x);rot(x);
}
up(x);
}
void insert(int x)
{
++n;
v[n]=x;sz[n]=1;
if(!rt)
{
rt=n;return ;
}
int i=rt;
while(1)
{
bool d=v[i]<x;
if(c[i][d]) i=c[i][d];
else
{
sc(i,n,d);
splay(n);
return ;
}
}
}
map<int,int>dy;
int DY(int x)
{
if(!dy.count(x))return x;
return dy[x];
}
int find_by_rank(int x)
{
if(!rt)return DY(x);
int i=rt,i0=0,rk=1;
while(i)
{
i0=i;
if(x>v[i]-(sz[cl(i)]+rk))
{
rk+=sz[cl(i)]+1;
i=c[i][1];
}
else i=c[i][0];
}
splay(i0);
return DY(x+rk-1);
}
}out;
const int PRE=1,SUF=2;
struct point
{
int in,id;
};
map<int,point>belong;//i de wei zhi
point &B(int x)
{
if(!belong.count(x))belong[x]=(point){0,x};
return belong[x];
}
int rk(int x)
{
if(B(x).in==1)
{
return pre.a[1]+1 - pre.rank(B(x).id);
}
if(B(x).in==2)
{
return n-suf.a[1]+suf.rank(B(x).id);
}
return pre.a[1]+out.rank(B(x).id);
}
int find_by_rank(int x)
{
if(x<=pre.a[1]) return pre.find_by_rank(pre.a[1]-x+1);
if(x>n-suf.a[1]) return suf.find_by_rank(x-(n-suf.a[1]));
return out.find_by_rank(x-pre.a[1]);
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
n=read();m=read();
for(d=1;d<m;d<<=1);d-=1;
lastans=0;
while(m--)
{
int type=read(),x=r(),ans;
if(type==4)
{
ans=find_by_rank(x);
}
else
{
ans=rk(x);
if(type==1)
{
int y=r();
B(y)=B(x);
if(B(x).in) (B(x).in==PRE?pre:suf).id[B(x).id]=y;
else out.dy[B(x).id]=y;
}
else
{
if(B(x).in==0) out.insert(B(x).id);
else
(B(x).in==PRE?pre:suf).del(B(x).id);
if(type==2) B(x)=(point){PRE,pre.insert(x)};
else B(x)=(point){SUF,suf.insert(x)};
}
}
printf("%d\n",lastans=ans);
}
}