bzoj2209(splay)

本文介绍了一种基于树状结构实现区间操作与查询的方法。通过构建特殊的树结构,支持对区间进行翻转、取反等操作,并能快速计算区间的最大最小值。适用于解决复杂的数据结构问题。

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

debug很爽,表示细节错误一个有一个。

注意:1:在更新打标记时,要把原始数据和维护数据一起更新!!

2:在序列问题中,查找一个数只能用size找排名来找,因为,序列可能翻转!!

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<stack>
using namespace std;
const int N=100005;

int n,m,a[N];
char s[N];

int fa[N],ch[N][2],rev[N],fz[N],rt,mxl[N],mxr[N],mil[N],mir[N],sum[N],size[N];

void up(int i)
{
	int l=ch[i][0],r=ch[i][1];
	size[i]=size[l]+size[r]+1;
	sum[i]=sum[l]+sum[r]+a[i];
	
	mxl[i]=max(0,max(sum[l]+a[i]+mxl[r],mxl[l]));
	mxr[i]=max(0,max(sum[r]+a[i]+mxr[l],mxr[r]));
	
	mil[i]=min(0,min(sum[l]+a[i]+mil[r],mil[l]));
	mir[i]=min(0,min(sum[r]+a[i]+mir[l],mir[r]));
}

int build(int fat,int l,int r)
{
	if (l>r) return 0;
	int mid=(l+r)>>1;
	fa[mid]=fat;size[mid]=1;
	ch[mid][0]=build(mid,l,mid-1);
	ch[mid][1]=build(mid,mid+1,r);
	up(mid);
	return mid;
}
void down(int i)
{
	int pos,l=ch[i][0],r=ch[i][1];
	if (fz[i])
	{
		fz[i]^=1,fz[l]^=1,fz[r]^=1;
		sum[l]=-sum[l],sum[r]=-sum[r];
		for (int j=0;j<=1;j++)
		{
			pos=ch[i][j];
			a[pos]=-a[pos];
			swap(mxl[pos],mil[pos]);
			mxl[pos]=-mxl[pos];
			mil[pos]=-mil[pos];
			swap(mxr[pos],mir[pos]);
			mxr[pos]=-mxr[pos];
			mir[pos]=-mir[pos];		
		}
	}
	if (rev[i])
	{
		rev[i]^=1,rev[l]^=1,rev[r]^=1;
		swap(ch[i][0],ch[i][1]);
		
		swap(mxl[l],mxr[l]);
		swap(mil[l],mir[l]);
		
		swap(mxl[r],mxr[r]);
		swap(mil[r],mir[r]);
	}
}
stack<int> ss;
void rotate(int x)  
{  
    int y=fa[x],z=fa[y],l,r;  
    if (ch[y][0]==x) l=0;else l=1;r=l^1;  
    if (z) if (ch[z][0]==y) ch[z][0]=x;else ch[z][1]=x;  
    fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;  
    ch[y][l]=ch[x][r];ch[x][r]=y; 
	up(y); 
}  
void splay(int x,int k)  
{  
    int y,z;  
    while (fa[x]!=k)  
    {  
        y=fa[x];z=fa[y];  
        if (z!=k)  
        {  
            if ((ch[z][0]==y)^(ch[y][0]==x)) rotate(x);else rotate(y);  
        }  
        rotate(x);  
    }  
    if (k==0) rt=x;
	up(x); 
}  
int find_kth(int u,int k)//必须用名次查找位置!!!
{
	down(u);
	if (size[ch[u][0]]+1==k) return u;
	if (size[ch[u][0]]>=k) return find_kth(ch[u][0],k);
	return find_kth(ch[u][1],k-size[ch[u][0]]-1);
}
int split(int x,int y)
{
	int posx=find_kth(rt,x-1);splay(posx,0);
	int posy=find_kth(rt,y+1);splay(posy,posx);
	return ch[posy][0];
}
inline int read()
{
	int ans;char ch;
	while ((ch=getchar())<'0'||ch>'9');ans=ch-'0';
	while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
	return ans;
}
int main()
{
	n=read(),m=read();
	scanf("%s",s+1);
	
	for (int i=2;i<=n+1;i++) if (s[i-1]=='(') a[i]=1;else a[i]=-1;
	a[1]=a[n+2]=0;
	
	rt=build(0,1,n+2);
	
	int t,x,y,pos;
	for (int i=1;i<=m;i++)
	{
		t=read(),x=read(),y=read();
		x++,y++;
		pos=split(x,y);
		switch(t)
		{
			case 0:
				printf("%d\n",-(mil[pos]-1)/2+(mxr[pos]+1)/2);
				break;
			case 1:
				fz[pos]^=1;
				a[pos]=-a[pos];//注意把原始数据更新!!查了好长时间
				sum[pos]=-sum[pos];
				swap(mxl[pos],mil[pos]);
				mxl[pos]=-mxl[pos];
				mil[pos]=-mil[pos];
				swap(mxr[pos],mir[pos]);
				mxr[pos]=-mxr[pos];
				mir[pos]=-mir[pos];
				up(fa[pos]);up(rt);
				break;
			case 2:
				rev[pos]^=1;
				swap(mxl[pos],mxr[pos]);
				swap(mil[pos],mir[pos]);
				up(fa[pos]),up(rt);
				break;
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值