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));
}
}