[BZOJ3223]文艺平衡树(平衡树splay)

本文介绍了一种基于平衡树的数据结构实现区间翻转的方法。通过详细的代码示例,展示了如何进行节点旋转、维护节点信息及执行区间翻转操作。适用于解决涉及区间更新和查询的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

我是超链接

题解:

平衡树基本操作----区间翻转

在这个题中,点的排名就是点的值,可以少写一步

代码:


#include <cstdio>
#include <iostream>
using namespace std;
const int N=100005;
int ch[N][2],f[N],size[N],delta[N],root,sz,key[N],n;
int get(int x){return ch[f[x]][1]==x;}
void updata(int now){size[now]=size[ch[now][0]]+size[ch[now][1]]+1;}
void pushdown(int now)
{
	if (delta[now])
	{
		swap(ch[now][0],ch[now][1]);
		delta[ch[now][0]]^=1;
		delta[ch[now][1]]^=1;
		delta[now]=0;
	}
}
void rotate(int x)
{
	pushdown(f[x]);
	pushdown(x);
	int old=f[x],oldf=f[old],which=get(x);
	f[x]=oldf; if (oldf) ch[oldf][ch[oldf][1]==old]=x;
	ch[old][which]=ch[x][which^1]; f[ch[x][which^1]]=old;
	ch[x][which^1]=old; f[old]=x;
	updata(old); updata(x);
}
void splay(int x,int to)
{
	for (;f[x]!=to;rotate(x))
	  if (f[f[x]]!=to) rotate(get(x)==get(f[x])?f[x]:x);
	if (!to) root=x; 
}
int build(int fa,int l,int r)
{
	if (l>r) return 0;
	int mid=(l+r)>>1;
	int now=++sz;
	key[now]=mid; f[now]=fa; 
	int lch=build(now,l,mid-1);
	int rch=build(now,mid+1,r);
	ch[now][0]=lch; ch[now][1]=rch;
	updata(now);
	return now;
}
int find(int x)//位置为x的编号 
{
	int now=root;
	while (1)
	{
		pushdown(now);
		if (x<=size[ch[now][0]]) now=ch[now][0];
		else
		{
			x-=size[ch[now][0]]+1;
			if (!x) return now;
			now=ch[now][1];
		}
	}
}
void rev(int l,int r)
{
	l--;r++;
	if (l==0 && r>n){delta[root]^=1;return;}
	if (l==0)
	{
		int x=find(r);
		splay(x,0);
		delta[ch[root][0]]^=1;
		return;
	}
	if (r>n)
	{
		int x=find(l);
		splay(x,0);
		delta[ch[root][1]]^=1;
		return;
	}
	int x=find(l),y=find(r);
	splay(x,0); splay(y,x);
	delta[ch[ch[root][1]][0]]^=1;
}
void print(int now)
{
	pushdown(now);
	if (ch[now][0]) print(ch[now][0]);
	printf("%d ",key[now]);
	if (ch[now][1]) print(ch[now][1]);
}
int main()
{
	int m;scanf("%d%d",&n,&m);
	root=build(0,1,n);
	for (int i=1;i<=m;i++)
	{
		int x,y;scanf("%d%d",&x,&y);
		rev(x,y);
	}
	print(root);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值