[AH2017/HNOI2017]单旋

XXVI.[AH2017/HNOI2017]单旋

先从单旋最小/大值的操作看起。手动模拟一下的话就会发现它对整棵树的形态几乎没有影响,就是断开最小值与它父亲的连边,并用其原本的右儿子(如果存在)替代。之后,将整棵树的根设作其新右儿子。最大值同理。

然后删除最小值也类似。注意删除一个原本就在树顶的最小值意味着要更新树根。

现在考虑比较玄乎的插入操作。明显,其要么插入到前驱的右儿子,要么插入到后继的左儿子,并且依照建树的方法,其前驱与后继在未插入之前必然是父子关系。所以我们只需插入到其中更深的一个即可。

前驱后继随便开个 set 维护即可。断边连边并求深度可以用LCT维护。

(附:因为其并不会大幅度改变深度,最多只是在单旋最大最小值的时候将其余点的深度全部升高了一,但是这个可以通过打全局 tag 简单处理,所以实际上也可以不用 LCT,不过那样讨论起来太麻烦,就懒得那么搞了)

时间复杂度 \(O(n\log n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
int m,cnt,FA[100100],LS[100100],RS[100100],rt;
#define lson t[x].ch[0]
#define rson t[x].ch[1]
struct LCT{int ch[2],fa,sz;bool rev;}t[100100];
void REV(int x){swap(lson,rson),t[x].rev^=1;}
void pushdown(int x){if(!t[x].rev)return;if(lson)REV(lson);if(rson)REV(rson);t[x].rev=false;}
void pushup(int x){t[x].sz=t[lson].sz+t[rson].sz+1;}
int identify(int x){if(t[t[x].fa].ch[0]==x)return 0;if(t[t[x].fa].ch[1]==x)return 1;return -1;}
void rotate(int x){
	int y=t[x].fa,z=t[y].fa,dirx=identify(x),diry=identify(y),b=t[x].ch[!dirx];
	if(diry!=-1)t[z].ch[diry]=x;t[x].fa=z;
	if(b)t[b].fa=y;t[y].ch[dirx]=b;
	t[x].ch[!dirx]=y,t[y].fa=x,pushup(y),pushup(x);
}
void pushall(int x){if(identify(x)!=-1)pushall(t[x].fa);pushdown(x);}
void splay(int x){for(pushall(x);identify(x)!=-1;rotate(x))if(identify(t[x].fa)!=-1)rotate(identify(t[x].fa)==identify(x)?t[x].fa:x);}
void access(int x){for(int y=0;x;x=t[y=x].fa)splay(x),rson=y,pushup(x);}
void makeroot(int x){access(x),splay(x),REV(x);}
void link(int x,int y){access(x),splay(x),t[x].fa=y;}
int split(int x,int y){makeroot(x),access(y),splay(y);return t[y].sz;}
void cut(int x,int y){split(x,y);t[y].ch[0]=t[x].fa=0,pushup(y);}
set<pair<int,int> >s;
int insert(int k){
	int x=++cnt;if(s.empty()){s.emplace(k,x),rt=x,pushup(x);return 1;}
	auto it=s.lower_bound(make_pair(k,0));int bef=-1,aft=-1;
	if(it!=s.end())aft=it->second;if(it!=s.begin())bef=(--it)->second;s.emplace(k,x);
	if(aft==-1){link(x,FA[x]=bef),RS[bef]=x;return split(rt,x);}
	if(bef==-1){link(x,FA[x]=aft),LS[aft]=x;return split(rt,x);}
	int BF=split(rt,bef),AF=split(rt,aft);link(x,FA[x]=(BF>AF?bef:aft)),(BF>AF?RS[bef]:LS[aft])=x;return max(BF,AF)+1;
}
int rotatemin(){
	int x=s.begin()->second,ret=split(rt,x);
	if(x!=rt){
		LS[FA[x]]=RS[x],cut(x,FA[x]);
		if(RS[x])cut(x,RS[x]),link(RS[x],FA[x]),FA[RS[x]]=FA[x];
		link(x,rt),FA[x]=0,FA[rt]=x,RS[x]=rt,rt=x;
	}
	return ret;
}
int rotatemax(){
	int x=s.rbegin()->second,ret=split(rt,x);
	if(x!=rt){
		RS[FA[x]]=LS[x],cut(x,FA[x]);
		if(LS[x])cut(x,LS[x]),link(LS[x],FA[x]),FA[LS[x]]=FA[x];
		link(x,rt),FA[x]=0,FA[rt]=x,LS[x]=rt,rt=x;
	}
	return ret;
}
int delmin(){
	int x=s.begin()->second,ret=split(rt,x);s.erase(s.begin());
	if(x!=rt){
		cut(x,FA[x]),LS[FA[x]]=RS[x];
		if(RS[x])cut(x,RS[x]),link(RS[x],FA[x]),FA[RS[x]]=FA[x];
		FA[x]=0;
	}else if(RS[x])cut(x,RS[x]),FA[rt=RS[x]]=0;else rt=0;
	return ret;
}
int delmax(){
	int x=s.rbegin()->second,ret=split(rt,x);s.erase(--s.end());
	if(x!=rt){
		cut(x,FA[x]),RS[FA[x]]=LS[x];
		if(LS[x])cut(x,LS[x]),link(LS[x],FA[x]),FA[LS[x]]=FA[x];
		FA[x]=0;
	}else if(LS[x])cut(x,LS[x]),FA[rt=LS[x]]=0;else rt=0;
	return ret;
}
int main(){
//	freopen("4.in","r",stdin);
	scanf("%d",&m);
	for(int i=1,tp,x;i<=m;i++){
		scanf("%d",&tp);
		if(tp==1)scanf("%d",&x),printf("%d\n",insert(x));
		if(tp==2)printf("%d\n",rotatemin());
		if(tp==3)printf("%d\n",rotatemax());
		if(tp==4)printf("%d\n",delmin());
		if(tp==5)printf("%d\n",delmax());
//		printf("-----%d-----\n",rt);
//		for(int j=1;j<=cnt;j++)printf("%d:[%d,%d]:%d\n",j,LS[j],RS[j],FA[j]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Troverld/p/14602267.html