1. 程式人生 > 其它 >luogu P3721 [AH2017/HNOI2017]單旋

luogu P3721 [AH2017/HNOI2017]單旋

題面傳送門
感覺不是很難但就是想了挺久?
首先肯定不能暴力splay單旋,肯定被卡掉。
我們考慮一次單旋有啥性質:可以發現是左子樹深度整體減一,右子樹深度不變,父親和兄弟深度整體加一。
同時父親和兄弟轉了一次之後就變成了右子樹就不變了。
考慮操作二,相當於撇開左子樹不看剩下的就是把除了右子樹之外的點深度加一。
但是這個是最小值根被沒有左子樹啊,所以可以值域上維護一個線段樹,然後二分出右子樹的範圍,就可以區間加了。
後面三個操作同理,第一個操作開個set找前驅後繼就好了。
時間複雜度\(O(n\log n)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M ((1<<20)+5)
#define Ks (12+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;set<int> F;set<int>::it P1,P2;
int n,m,k,x,y,z,Op[N],X[N],Ns[N],Nh;
namespace Tree{
	#define ls now<<1
	#define rs now<<1|1
	int Mx[N<<2],Fl[N<<2];I void BD(){Me(Mx,0x3f);}I void Up(int now){Mx[now]=min(Mx[ls],Mx[rs]);}
	I void PF(int now,int w){Fl[now]+=w;Mx[now]+=w;}I void P(int now){Fl[now]&&(PF(ls,Fl[now]),PF(rs,Fl[now]),Fl[now]=0);}
	I void Ins(int x,int y,int l=1,int r=Nh,int now=1){if(l==r){Mx[now]=y;return;}P(now);int m=l+r>>1;x<=m?Ins(x,y,l,m,ls):Ins(x,y,m+1,r,rs);Up(now);}
	I void ADD(int x,int y,int z,int l=1,int r=Nh,int now=1){if(x>y) return;if(x<=l&&r<=y) return PF(now,z);int m=l+r>>1;P(now);x<=m&&(ADD(x,y,z,l,m,ls),0);y>m&&(ADD(x,y,z,m+1,r,rs),0);Up(now);}
	I int Qry(int x,int l=1,int r=Nh,int now=1){if(l==r) return Mx[now];P(now);int m=l+r>>1;return x<=m?Qry(x,l,m,ls):Qry(x,m+1,r,rs);}
	I int F1(int x,int l=1,int r=Nh,int now=1){if(l==r) return l-(Mx[now]<x);int m=l+r>>1;P(now);return Mx[ls]>=x?F1(x,m+1,r,rs):F1(x,l,m,ls);}
	I int F2(int x,int l=1,int r=Nh,int now=1){if(l==r) return l+(Mx[now]<x);int m=l+r>>1;P(now);return Mx[rs]>=x?F2(x,l,m,ls):F2(x,m+1,r,rs);}
	#undef ls
	#undef rs
}
int main(){
	freopen("1.in","r",stdin);
	int i,j;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d",&Op[i]),Op[i]==1&&(scanf("%d",&X[i]),Ns[++Nh]=X[i]);Tree::BD();
	sort(Ns+1,Ns+Nh+1);Nh=unique(Ns+1,Ns+Nh+1)-Ns-1;for(i=1;i<=n;i++) {
		if(Op[i]==1){
			X[i]=LB(Ns+1,Ns+Nh+1,X[i])-Ns;if(F.empty()){Tree::Ins(X[i],1);puts("1");F.insert(X[i]);continue;}
			P1=P2=F.LB(X[i]);if(P1==F.end()) P2--,Tree::Ins(X[i],z=Tree::Qry(*P2)+1);
			else if(P1==F.begin()) Tree::Ins(X[i],z=Tree::Qry(*P1)+1);
			else x=Tree::Qry(*P1),y=Tree::Qry(*(--P2)),Tree::Ins(X[i],z=max(x,y)+1);F.insert(X[i]);printf("%d\n",z);
		} else if(Op[i]==2||Op[i]==4) printf("%d\n",x=Tree::Qry(*F.begin())),Op[i]^4?(Tree::ADD(Tree::F1(x)+1,Nh,1),Tree::Ins(*F.begin(),1)):(Tree::Ins(*F.begin(),1e9),F.erase(F.begin()),Tree::ADD(1,Tree::F1(x),-1));
		else printf("%d\n",x=Tree::Qry(*F.rbegin())),Op[i]^5?(Tree::ADD(1,Tree::F2(x)-1,1),Tree::Ins(*F.rbegin(),1)):(Tree::Ins(*F.rbegin(),1e9),F.erase(*F.rbegin()),Tree::ADD(Tree::F2(x),Nh,-1));
	}
}