ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P3721 [AH2017/HNOI2017]单旋 题解

2022-04-21 20:32:42  阅读:150  来源: 互联网

标签:ch return int 题解 void P3721 fa HNOI2017 inline


题目链接

这是一道很有意思的题……用一个数据结构维护另一个数据结构……

先考虑这个题的答案,也就是深度如何维护?作为 LCT 练习题单中的一道题,很容易想到用 LCT 维护链上点数,这样每个点的深度就可以把这个点和根 split 出来,直接返回这个点的 siz 就行了。

然后,考虑到需要找整棵树的最小点和最大点,所以使用 set 来维护整棵树中存在的点,找最小和最大就调用 t.begin()t.end() 即可。(注意 end() 是开的,需要 --it 才能找到最大的元素)

考虑剩下四个操作树的形态会发生哪些变化:

2、3 操作:把最小的或者最大的数移到根。以最小的为例:设这个点为 \(x\),这个点一定没有左儿子,右儿子为 \(u\),父亲为 \(v\),根为 \(rt\),那么需要做的操作是 cut(x,u),cut(x,v),link(u,v),link(x,rt)。这个大家画个图就理解了。那么有一个问题,如何找到这个 \(u\) 和 \(v\) 呢?需要用数组模拟一下原树的结构,在插入、旋转和删除的时候更新一下即可,具体细节看代码。

4、5 操作:移到根之后要删除,所以最后那个 link(x,rt) 就不需要做了。

总体来说,这个方法码量较大,对码力要求较高且难调,如果有其他更好方法,不建议使用……但是如果真的想练习 LCT,本题不失为一道好题。

点击查看代码
#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
inline void swap(int &x,int &y){x^=y^=x^=y;}
inline int max(const int &a,const int &b){return a>b?a:b;}
const int N=1e5+13;
struct Lct{
	struct Stack{
		int s[N],t;
		inline void clear(){t=0;}
		Stack(){clear();}
		inline void push(int x){s[++t]=x;}
		inline void pop(){--t;}
		inline int top(){return s[t];}
		inline bool empty(){return !t;}
	};
	int fa[N],siz[N],ch[N][2];bool tag[N];
	inline void refresh(int x){siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
	inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
	inline bool chk(int x){return ch[fa[x]][1]==x;}
	inline void rotate(int x){
		int f=fa[x],gf=fa[f],k=chk(x),w=ch[x][k^1];
		fa[x]=gf;if(!isroot(f)) ch[gf][chk(f)]=x;
		if(w) fa[w]=f;ch[f][k]=w;
		fa[f]=x;ch[x][k^1]=f;
		refresh(f),refresh(x);
	}
	inline void pushdown(int x){
		if(!tag[x]) return;
		tag[ch[x][0]]^=1,tag[ch[x][1]]^=1,tag[x]=0;
		swap(ch[x][0],ch[x][1]);
	}
	inline void splay(int x){
		Stack st;int p=x;
		while(!isroot(p)) st.push(p),p=fa[p];
		st.push(p);
		while(!st.empty()) pushdown(st.top()),st.pop();
		while(!isroot(x)){
			int f=fa[x];
			if(!isroot(f)){
				if(chk(f)==chk(x)) rotate(f);
				else rotate(x);
			}
			rotate(x);
		}
	}
	inline void access(int x){
		for(int p=0;x;p=x,x=fa[x]) splay(x),ch[x][1]=p,refresh(x);
	}
	inline void makeroot(int x){access(x);splay(x);tag[x]^=1;}
	inline int findroot(int x){
		access(x);splay(x);
		while(ch[x][0]) x=ch[x][0];
		return x;
	}
	inline void split(int x,int y){makeroot(x);access(y);splay(y);}
	inline void link(int x,int y){
		if(!x||!y) return;
		makeroot(x);
		fa[x]=y;
	}
	inline void cut(int x,int y){
		if(!x||!y) return;
		split(x,y);
		ch[y][0]=fa[x]=0,refresh(x),refresh(y);
	}
	inline int finddep(int x,int y){//对每一个点找深度 
		split(x,y);
		return siz[y];
	}
}T;
int m,tot,rt,op[N],a[N],b[N],Cnt,f[N],c[N][2];
set<int> t;
set<int>::iterator it;
int main(){
//	freopen("splay1.in","r",stdin);
//	freopen("splay.out","w",stdout);
	scanf("%d",&m);
	for(int i=1;i<=m;++i) T.siz[i]=1;
	for(int i=1;i<=m;++i){
		scanf("%d",&op[i]);
		if(op[i]==1) scanf("%d",&a[i]),b[++tot]=a[i];
	}
	sort(b+1,b+tot+1);tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=m;++i){
		switch(op[i]){
			case 1:{
				int x=lower_bound(b+1,b+tot+1,a[i])-b;
				int pre=0,suf=0;
				if(!Cnt){//注意特判,这个题因为涉及到边界的地方很多,所以需要很多特判 
					t.insert(x);rt=x;
					puts("1");++Cnt;
					continue;
				}
				t.insert(x);it=t.find(x);++Cnt;
				if(it!=t.begin()) pre=*(--it),++it;//找前驱和后继的set操作不太一样,要注意 
				++it;
				if(it!=t.end()) suf=*it;
				int r1=pre?T.finddep(rt,pre):0,r2=suf?T.finddep(rt,suf):0;
				if(r1<r2){
					printf("%d\n",r2+1);
					f[x]=suf,c[suf][0]=x,T.link(x,suf);
				}
				else{
					printf("%d\n",r1+1);
					f[x]=pre,c[pre][1]=x,T.link(x,pre);
				}
				break;
			}
			case 2:{
				it=t.begin();int x=*it;
				if(rt==x){puts("1");continue;}
				printf("%d\n",T.finddep(rt,x));
				int u=c[x][1],v=f[x];//开了两个数组来记录原树 
				T.cut(x,v),T.cut(x,u),T.link(x,rt),T.link(v,u);
				f[x]=0,c[x][1]=rt,f[rt]=x;rt=x;
				c[v][0]=u;f[u]=v;
				break;
			}
			case 3:{
				it=t.end();int x=*(--it);
				if(rt==x){puts("1");continue;}
				printf("%d\n",T.finddep(rt,x));
				int u=c[x][0],v=f[x];
				T.cut(x,v),T.cut(x,u),T.link(x,rt),T.link(v,u);
				f[x]=0,c[x][0]=rt,f[rt]=x;rt=x;
				c[v][1]=u;f[u]=v;
				break;
			}
			case 4:{
				it=t.begin();int x=*it;t.erase(x);
				printf("%d\n",T.finddep(rt,x));
				--Cnt;
				if(!Cnt) continue;
				int u=c[x][1],v=f[x];
				T.cut(x,v),T.cut(x,u);T.link(u,v);
				c[x][0]=c[x][1]=f[x]=0;if(rt==x) rt=u;//别忘了更新根节点 
				c[v][0]=u;f[u]=v;
				break;
			}
			case 5:{
				it=t.end();int x=*(--it);t.erase(x);
				printf("%d\n",T.finddep(rt,x));
				--Cnt;
				if(!Cnt) continue;
				int u=c[x][0],v=f[x];
				T.cut(x,v),T.cut(x,u);T.link(u,v);
				c[x][0]=c[x][1]=f[x]=0;if(rt==x) rt=u;
				c[v][1]=u;f[u]=v;
				break;
			}
		}
	}
	return 0;
}

标签:ch,return,int,题解,void,P3721,fa,HNOI2017,inline
来源: https://www.cnblogs.com/winterfrost/p/p3721-solution.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有