P3721 [AH2017/HNOI2017]单旋

题目

P3721 [AH2017/HNOI2017]单旋

毒瘤的\(HNOI\),其实想清楚了不难

做法

首先这题不去考虑单纯\(splay\)的做法,单旋肯定会卡掉,不知道具体卡了多少分

这题是只用单旋,当然去手玩一下,这时候你就知道上旋最小值和最大值的子树变化规律了,线段树维护深度

然后其实就只考虑插入就好了,把\(splay\)的权值排列一下,显然相邻两个在\(splay\)里也相邻

也就是只有两种形态,每种形态能插的地方只有一个,且另一种形态这个地方不为空,枚举一下就好了

\(LCT\)维护深度也是种经典套路,但用线段树更有意思

My complete code

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
typedef int LL;
const LL maxn=1e6;
inline LL Read(){
	LL x(0),f(1);char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
set<LL> Set;
struct node{
	LL op,a;
}q[maxn];
LL n,tot,root,Root,nod;
LL lazy[maxn],dep[maxn],lc[maxn],rc[maxn],b[maxn],son[maxn][2],fa[maxn];
inline void Pushdown(LL now){
	if(lazy[now]){
		LL val(lazy[now]); lazy[now]=0;
		if(!lc[now])lc[now]=++nod;
		if(!rc[now])rc[now]=++nod;
		lazy[lc[now]]+=val,dep[lc[now]]+=val;
		lazy[rc[now]]+=val,dep[rc[now]]+=val;
	}
}
void Add(LL &now,LL l,LL r,LL lt,LL rt,LL val){
	if(!now) now=++nod;
	if(lt<=l&&rt>=r){
		dep[now]+=val,lazy[now]+=val;
		return;
	}
	Pushdown(now);
	LL mid(l+r>>1);
	if(lt<=mid) Add(lc[now],l,mid,lt,rt,val);
	if(rt>mid) Add(rc[now],mid+1,r,lt,rt,val);
}
void Change(LL &now,LL l,LL r,LL c,LL val){
	if(!now) now=++nod;
	if(l==r){
		dep[now]=val;
		return;
	}
	Pushdown(now);
	LL mid(l+r>>1);
	if(c<=mid) Change(lc[now],l,mid,c,val);
	else Change(rc[now],mid+1,r,c,val);
}
LL Query(LL now,LL l,LL r,LL c){
	if(l==r) return dep[now];
	Pushdown(now);
	LL mid(l+r>>1);
	if(c<=mid)
	    return Query(lc[now],l,mid,c);
	else
	    return Query(rc[now],mid+1,r,c);
}
inline LL Insert(LL x){
	set<LL> ::iterator it=Set.insert(x).first;
	if(!root){
		Root=x; Change(root,1,tot,x,1); return 1;
	}
	if(it!=Set.begin()){
		if(!son[*--it][1]){
			son[*it][1]=x;
			fa[x]=*it;
		}
		++it;
	}
	if(!fa[x]){
		son[*++it][0]=x;
		fa[x]=*it;
	}
	LL deep(Query(root,1,tot,fa[x])+1);
	Change(root,1,tot,x,deep);
	return deep;
}
inline LL Splaymin(){
	LL x=*Set.begin(),deep(Query(root,1,tot,x));
	if(x==Root) return 1;
	if(x+1<=fa[x]-1)
	    Add(root,1,tot,x+1,fa[x]-1,-1);
	Add(root,1,tot,1,tot,1);
	son[fa[x]][0]=son[x][1];
	fa[son[x][1]]=fa[x];
	son[x][1]=Root;
	fa[Root]=x;
	Root=x;
	Change(root,1,tot,Root,1);
	return deep;
}
inline void Delmin(){
	printf("%d\n",Splaymin());
	Add(root,1,tot,1,tot,-1);
	Set.erase(Root);
	LL tmp(son[Root][1]); son[Root][1]=fa[Root]=0; Root=tmp;
	fa[Root]=0;
}
inline LL Splaymax(){
	LL x=*Set.rbegin(),deep(Query(root,1,tot,x));
	if(x==Root) return 1;
	if(fa[x]+1<=x-1)
	    Add(root,1,tot,fa[x]+1,x-1,-1);
	Add(root,1,tot,1,tot,1);
	son[fa[x]][1]=son[x][0];
	fa[son[x][0]]=fa[x];
	son[x][0]=Root;
	fa[Root]=x;
	Root=x;
	Change(root,1,tot,Root,1);
	return deep;
}
inline void Delmax(){
	printf("%d\n",Splaymax());
	Add(root,1,tot,1,tot,-1);
	Set.erase(Root);
	LL tmp(son[Root][0]); son[Root][0]=fa[Root]=0; Root=tmp;
	fa[Root]=0;
}
int main(){
	n=Read();
	for(LL i=1;i<=n;++i){
		q[i].op=Read();
		if(q[i].op==1)
			b[++tot]=q[i].a=Read();
	}
	sort(b+1,b+1+tot),tot=unique(b+1,b+1+tot)-b-1;
	for(LL i=1;i<=n;++i){
		if(q[i].op==1) printf("%d\n",Insert(lower_bound(b+1,b+1+tot,q[i].a)-b));
		else if(q[i].op==2) printf("%d\n",Splaymin());
		else if(q[i].op==3) printf("%d\n",Splaymax());
		else if(q[i].op==4) Delmin();
		else Delmax();
	}
	return 0;
}
posted @ 2019-01-27 16:52  y2823774827y  阅读(199)  评论(0编辑  收藏  举报