[AH2017/HNOI2017]单旋,洛谷P3721,模拟+维护

本文深入探讨了SPALY树的性质及其在数据结构中的应用,特别是通过树状数组进行区间操作的高效实现。文章分析了在SPALY树中插入节点时的前驱后继关系,以及如何利用树状数组维护节点深度,为解决复杂的数据结构问题提供了新的视角。

正题

      还挺有意思.

      手玩一下很容易就可以发现当一个最值spaly的时候只会更改O(1)个节点的关系,并且子树的深度不变,其余深度+1.

      一直卡在怎么插入,看题解发现相当于在前驱和后继里面找一个深度最大的,这个很容易证明,首先前驱后继一定是当前点的祖先,因为这个点没有儿子,所以拍扁的时候前驱就是向上走第一个左父亲,后继就是第一个右父亲,深度谁大当然就谁当父亲了.

      然后要维护深度的区间加,单点更改,单点查询,直接树状数组就可以.

总结

       这玩意性质难找,但找到显然.

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;

const int N=100010;
#define pii pair<int ,int>
struct ques{
	int type,x;
}q[N];
struct node{
	int ls,rs,fa;
}s[N];
pii a[N];
int n,m,num[N],X,rt,tot;
long long sum[N],dep,pre;
set<int> S;
set<int>::iterator it;

bool cmp(const pii&a,const pii&b){return a.first<b.first;}
void add(int x,long long t){for(int i=x;i<=n;i+=lowbit(i)) sum[i]+=t;}
long long gs(int x){long long tot=0;for(int i=x;i;i-=lowbit(i)) tot+=sum[i];return tot;}
void sn(int x,int t){pre=gs(x);add(x,t-pre);add(x+1,pre-t);}

void ins(int x){
	s[x].ls=s[x].rs=s[x].fa=0;
	if(rt==0) rt=x,dep=1;
	else{ 
		it=S.lower_bound(x);
		if(it!=S.end() && !s[*it].ls) s[X=*it].ls=x;
		else it--,s[X=*it].rs=x;
		s[x].fa=X;dep=gs(X)+1;
	}
	S.insert(x);sn(x,dep);
}

void zig(){
	it=S.begin();X=*it;dep=gs(X);
	if(X!=rt) {
		add(1,1);
		if(X+1<=s[X].fa-1) add(X+1,-1),add(s[X].fa,1);
		sn(X,1);s[s[X].fa].ls=s[X].rs;s[s[X].rs].fa=s[X].fa;
		s[rt].fa=X;s[X].rs=rt;rt=X;s[X].fa=0;
	}
}

void zag(){
	it=S.end();it--;X=*it;dep=gs(X);
	if(X!=rt){
		add(1,1);
		if(s[X].fa+1<=X-1) add(s[X].fa+1,-1),add(X,1);
		sn(X,1);s[s[X].fa].rs=s[X].ls;s[s[X].ls].fa=s[X].fa;
		s[rt].fa=X;s[X].ls=rt;rt=X;s[X].fa=0;
	}
}

void zig_(){
	zig();add(1,-1);
	it=S.begin();S.erase(it);
	s[rt=s[rt].rs].fa=0;
}

void zag_(){
	zag();add(1,-1);
	it=S.end();it--;S.erase(it);
	s[rt=s[rt].ls].fa=0;
}

int main(){
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d",&q[i].type);
		if(q[i].type==1) scanf("%d",&q[i].x),a[++n].first=q[i].x,a[n].second=i;
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++) q[a[i].second].x=i;
	for(int i=1;i<=m;i++){
		if(q[i].type==1) ins(q[i].x);
		if(q[i].type==2) zig();
		if(q[i].type==3) zag();
		if(q[i].type==4) zig_();
		if(q[i].type==5) zag_();
		printf("%lld\n",dep);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值