1858: [Scoi2010]序列操作

本文深入探讨了线段树的数据结构及其应用,通过具体的代码示例展示了如何使用线段树进行区间更新和查询操作。文章还介绍了线段树的初始化过程及区间翻转等高级特性。

线段树

码不动。。。要提高代码能力!

多打几个标记就可以了 我写的有点麻烦。。。。


#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int init[100000+1];
struct H
{
	int size;
	int sum;
	int mark;
	int S1,L1,R1;
	int S0,L0,R0;
}seg[100000*4];

H Up(H L,H R)
{
	H ans;
	ans.size=L.size+R.size;
	ans.mark=-1;
	if(L.L0==L.size) ans.L0=L.L0+R.L0;
	else ans.L0=L.L0;
	
	if(L.L1==L.size) ans.L1=L.L1+R.L1;
	else ans.L1=L.L1;
	
	if(R.R0==R.size) ans.R0=R.R0+L.R0;
	else ans.R0=R.R0;
	if(R.R1==R.size) ans.R1=R.R1+L.R1;
	else ans.R1=R.R1;
	
	ans.sum=L.sum+R.sum;
	ans.S0=max(L.R0+R.L0,max(L.S0,R.S0));
	ans.S1=max(L.R1+R.L1,max(L.S1,R.S1));
	
	return ans;
}

void Build(int now,int l,int r)
{
	seg[now].size=r-l+1;
	seg[now].mark=-1;
	if(l==r)
	{
		if(init[l]) seg[now].sum=seg[now].L1=seg[now].R1=seg[now].S1=1;
		else seg[now].L0=seg[now].R0=seg[now].S0=1;
		return ;
	}
	int mid=(r+l)/2;
	Build(now*2,l,mid);
	Build(now*2+1,mid+1,r);
	seg[now]=Up(seg[now*2],seg[now*2+1]);
//	cout<<l<<' '<<r<<' '<<seg[now].sum<<endl;
}

void Pushdown(int now)
{
	H l=seg[now*2];
	H r=seg[now*2+1];
	if(seg[now].mark==-1) 
		return ;
	else if(seg[now].mark==0)
	{
		l.sum=l.mark=l.S1=l.L1=l.R1=0;
		l.S0=l.L0=l.R0=l.size;
		
		r.sum=r.mark=r.S1=r.L1=r.R1=0;
		r.S0=r.L0=r.R0=r.size;
		
		l.mark=r.mark=0;
	}
	else if(seg[now].mark==1)
	{
		l.sum=l.mark=l.S1=l.L1=l.R1=l.size;
		l.S0=l.L0=l.R0=0;
		
		r.sum=r.mark=r.S1=r.L1=r.R1=r.size;
		r.S0=r.L0=r.R0=0;
		
		l.mark=r.mark=1;
	}
	else
	{
		l.sum=l.size-l.sum;
		swap(l.L0,l.L1);
		swap(l.S0,l.S1);
		swap(l.R0,l.R1);
		
		r.sum=r.size-r.sum;
		swap(r.L0,r.L1);
		swap(r.S0,r.S1);
		swap(r.R0,r.R1);
		
		if(l.mark==-1)
			l.mark=2;
		else if(l.mark==0)
			l.mark=1;
		else if(l.mark==1)
			l.mark=0;
		else l.mark=-1;
		
		if(r.mark==-1)
			r.mark=2;
		else if(r.mark==0)
			r.mark=1;
		else if(r.mark==1)
			r.mark=0;
		else r.mark=-1;
	}
	seg[now].mark=-1;
	seg[now*2]=l;
	seg[now*2+1]=r;
}

void Change(int now,int l,int r,int s,int t,int x)
{
	if(l!=r) Pushdown(now);
	
	if(s<=l&&r<=t)
	{
		int size=seg[now].size;
		if(x==0)
			seg[now]=(H){size,0,0, 0,0,0, size,size,size};
		else if(x==1)
			seg[now]=(H){size,size,1, size,size,size, 0,0,0};
		else
		{
			seg[now].sum=seg[now].size-seg[now].sum;
			seg[now].mark=2;
			swap(seg[now].S1,seg[now].S0);
			swap(seg[now].L1,seg[now].L0);
			swap(seg[now].R1,seg[now].R0);
		}
		return ;
	}	
	int mid=(l+r)/2;
	if(s<=mid) Change(now*2,l,mid,s,t,x);
	if(mid+1<=t) Change(now*2+1,mid+1,r,s,t,x);
	seg[now]=Up(seg[now*2],seg[now*2+1]);//	
}

H Q(int now,int l,int r,int s,int t)
{
	if(s<=l&&r<=t){
	return seg[now];
	}
	Pushdown(now);
	int mid=(l+r)/2;
	H ans=(H){0,0,0, 0,0,0, 0,0,0};
	if(s<=mid) ans=Up(ans,Q(now*2,l,mid,s,t));
	if(mid+1<=t) ans=Up(ans,Q(now*2+1,mid+1,r,s,t));
	
	return ans;
}

int main()
{
	int n,m;
	cin >>n >>m;
	for(int i=1;i<=n;i++)
		scanf("%d",&init[i]);
	Build(1,1,n); 
	for(int i=1;i<=m;i++)
	{
		int opt,a,b;
		scanf("%d %d %d",&opt,&a,&b);
		
		a++,b++;
		if(opt<=2)
			Change(1,1,n,a,b,opt);
		else
		{
			H ans=Q(1,1,n,a,b);
			if(opt==3)
				printf("%d\n",ans.sum);
			else
				printf("%d\n",ans.S1);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值