zjoi2006 书架

动态序列的维护问题

也可以用文艺平衡树的方式来简化操作

#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
using namespace std;
const int N=2e5+10;
int read()
{
    int x=0,f=0,c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return f?-x:x; 
}

int sz[N],lch[N],rch[N],rnd[N],val[N],pos[N],fa[N];
int root,rx,ry,rz,cnt;
int n,m;

void SWAP(int x,int y)
{
	swap(val[x],val[y]); 
	pos[val[x]]=x; pos[val[y]]=y;
}

int _new(int x){sz[++cnt]=1; rnd[cnt]=rand(); val[cnt]=x; pos[x]=cnt; return cnt;}

void upd(int x){ sz[x]=sz[lch[x]]+sz[rch[x]]+1;}
//记录父亲的做法 
void split(int now,int k,int &x,int &y,int fax,int fay)
{
	if(!now){ x=y=0; return;}
	if(k>=sz[lch[now]]+1){ x=now;  fa[x]=fax; split(rch[now],k-sz[lch[now]]-1,rch[x],y,x,fay);}
	else {y=now; fa[y]=fay;  split(lch[now],k,x,lch[y],fax,y);}
	upd(now);
}

int merge(int x,int y)
{
	if(!x||!y) return x+y;
	if(rnd[x]<rnd[y]){ rch[x]=merge(rch[x],y);  fa[rch[x]]=x; upd(x); return x;}
	else { lch[y]=merge(x,lch[y]);  fa[lch[y]]=y; upd(y); return y;}
}

//需要获取编号为x的书本的位置
//但是平衡树中不记录下标  
//但是我们只需要在logn的时间里获得位置即可 因此暴力向上跳就可以 
int findp(int x,int rt)
{
	int p=pos[x],ret=0;
	ret+=sz[lch[p]]+1;
	while(p!=rt)
	{
		if( rch[fa[p]]==p ) ret+=sz[lch[fa[p]]]+1;
		p=fa[p];
	}
	return ret;
}
//调试的时候不要拿完全二叉树来调试 
//向着左上方向走的才会被记入答案中 
int findk(int k,int rt)
{
	int now=rt;
	while(1)
	{
		int lsz=sz[lch[now]],rsz=sz[rch[now]];
		if(k==lsz+1) return now;
		else if(k<lsz+1) now=lch[now];
		else now=rch[now],k=k-lsz-1;
	}
}

void Top(int x)
{
	int p=findp(x,root);
	split(root,p,rx,rz,0,0);
	split(rx,p-1,rx,ry,0,0);//连续分裂的根的问题 
	root=merge( merge(_new(x),rx),rz );

}

void Bottom(int x)
{
	int p=findp(x,root);
	split(root,p,rx,rz,0,0);
	split(rx,p-1,rx,ry,0,0);
	root=merge( merge(rx,rz),_new(x) );
}

void Insert(int x,int t)
{
	if(t==0) return;
	int p=findp(x,root);
	int q=findk(p+t,root);
	SWAP(pos[x],q);

}

int main()
{
	srand(1);
	n=read(); m=read();
	for(int i=1;i<=n;i++) 
	{
		int x=read();
		root=merge(root,_new(x));
	}
	for(int i=1;i<=m;i++)
	{
		char s[10]; scanf("%s",s);
		char c=s[0]; int x=read();
		if(c=='T') Top(x);
		else if(c=='B') Bottom(x);
		else if(c=='I') Insert(x,read());
		else if(c=='A') printf("%d\n",findp(x,root)-1);
		else printf("%d\n",val[findk(x,root)]);		
	}
}
posted @ 2022-03-19 14:35  __iostream  阅读(49)  评论(0)    收藏  举报