P2596 [ZJOI2006]书架

发布时间 2023-05-02 14:41:41作者: FJOI

\(\color{purple}\text{P2596 [ZJOI2006]书架}\)

解题方法

考虑使用 \(\text{FHQ}\) 平衡树 ,我们只使用编号,而不使用权值,平衡树上的先序遍历即为书的放置顺序。

  1. \(\text{Query}\) :这是最简单的操作,直接查询即可。
  2. \(\text{Ask}\):本题的核心,我们知道编号,因为没有权值,没法从根往下找到询问点,如果强制设权值会很麻烦。正难则反,既然我们知道询问点的编号,不如从询问点向上走回根,这个操作需要我们维护每个节点的父亲。(记得每次树改变时把根的父亲设为 \(0\)
  3. \(\text{Bottom/Top/Insert}\) 既然已经有了 \(Ask\) ,我们可以直接通过编号找到排名,继而分裂出需要改变的点,剩下的就是重新组合。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+110;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int n,m,rl[N],fx[N];
struct FHQ{
	int rt,x,y,z,cnt,phi;
	int ls[N],rs[N],rad[N],sze[N];
	int fa[N];
	void pushup(int u){sze[u]=sze[ls[u]]+sze[rs[u]]+1;return;} 
	int newnode(){
		rad[++cnt]=rand();
		sze[cnt]=1;
		return cnt;
	}
	void split(int u,int k,int &x,int &y,int fax,int fay){
		if(!u)x=0,y=0;
		else{
			if(k>sze[ls[u]]){
				x=u;fa[u]=fax;
				split(rs[u],k-sze[ls[u]]-1,rs[u],y,u,fay);
			}
			else{
				y=u;fa[u]=fay;
				split(ls[u],k,x,ls[u],fax,u);
			}
			pushup(u);
		}
		return;
	}
	int merge(int A,int B){
		if(!A || !B)return A+B;
		if(rad[A]<rad[B]){rs[A]=merge(rs[A],B);fa[rs[A]]=A;pushup(A);return A;}
		else {ls[B]=merge(A,ls[B]);fa[ls[B]]=B;pushup(B);return B;}
	}
	void insert(){rt=merge(rt,newnode());return;}
	int Query(int k){
		split(rt,k,x,z,0,0);
		split(x,k-1,x,y,fa[x],fa[y]);
		int tmp=y;rt=merge(merge(x,y),z);fa[rt]=0;
		return tmp;
	} 
	int ask(int x,int fr){
		if(x==0)return 0;
		if(fr==ls[x])return ask(fa[x],x);
		else return ask(fa[x],x)+sze[ls[x]]+1; 
	}
	int Ask(int x){return ask(fa[x],x)+sze[ls[x]];}
	void top(int k){
		split(rt,k-1,x,y,fa[x],fa[y]);
		split(y,1,y,z,fa[y],fa[z]);
		rt=merge(y,merge(x,z));fa[rt]=0;
	}
	void bottom(int k){
		split(rt,k-1,x,y,fa[x],fa[y]);
		split(y,1,y,z,fa[y],fa[z]);
		rt=merge(merge(x,z),y);fa[rt]=0;
	}
	void sap(int k,int t){
		if(t==-1){
			split(rt,k-2,x,y,fa[x],fa[y]);
			split(y,1,y,z,fa[y],fa[z]);
			split(z,1,z,phi,fa[z],fa[phi]);
			rt=merge(merge(x,z),merge(y,phi));fa[rt]=0;
		}
		if(t==1){
			split(rt,k-1,x,y,fa[x],fa[y]);
			split(y,1,y,z,fa[y],fa[z]);
			split(z,1,z,phi,fa[z],fa[phi]);
			rt=merge(merge(x,z),merge(y,phi));fa[rt]=0;
		}
		return;
	}
	void sd(int u){
		if(!u)return;
		cout<<u<<" "<<sze[u]<<" "<<ls[u]<<" "<<rs[u]<<" "<<fa[u]<<endl;
		sd(ls[u]);
		sd(rs[u]);
	}
	void Bark(){
		printf("-----------HYC is here-----------\n");
		sd(rt);
		printf("-----------HYC has gone-----------\n");
	}
}T;
int main(){
	srand(20230502);
	n=read(),m=read();
	for(int i=1;i<=n;i++)rl[i]=read(),fx[rl[i]]=i;//树编号-》实际编号;实际编号-》树编号 
	for(int i=1;i<=n;i++)T.insert();
//	T.Bark(); 
	for(int i=1;i<=m;i++){
		char opt[10];scanf("%s",opt);
		if(opt[0]=='Q'){int k=read();printf("%d\n",rl[T.Query(k)]);}
		if(opt[0]=='A'){int x=read();printf("%d\n",T.Ask(fx[x]));}
		if(opt[0]=='T'){int x=read();T.top(T.Ask(fx[x])+1);}
		if(opt[0]=='B'){int x=read();T.bottom(T.Ask(fx[x])+1);}
		if(opt[0]=='I'){int x=read(),t=read();T.sap(T.Ask(fx[x])+1,t);}
//		T.Bark(); 
	}
	return 0;
}