【SCOI2010】【线段树】序列操作

21 篇文章 0 订阅
15 篇文章 0 订阅

做这道题之前就知道这题比较恶心,但是为了保持心态也没当作很难的题来做。

维护的标记比较多一些

1、从左边开始的最多0的个数和1的个数

2、从右边开始的最多0的个数和1的个数

3、区间最大的0的个数和1的个数

4、区间0的个数和1的个数

5、是否反转

6、覆盖标记

有思路之后硬着头皮写,结果写下来一堆bug,改着比较烦,而且浪费时间。

比赛也没有那么多时间改bug,所以平时一定要养成注重细节的习惯不然代码量一大就很容易出错。

需要注意的是先处理覆盖情况再处理翻转情况,因为覆盖时是一定把翻转标记清除了的,所以只有可能先覆盖再翻转。

下面是代码(比较冗长):

#include<cstdio>
#include<cstring>
#define lson l,m,rt << 1
#define rson m+1,r,rt << 1 | 1
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100000 + 10;
struct tree
{
	int maxL0,maxR0,Max0;
	int maxL1,maxR1,Max1;
	int cover,cnt0,cnt1;
	bool reserve;
	tree()
	{
		maxL0 = maxR0 = Max0 = 0;
		maxL1 = maxR1 = Max1 = 0;
		reserve = false;
		cover = -1;
		cnt0 = cnt1 = 0;
	}
}Tree[maxn<<2],ans;
int n,m;
void init()
{
	freopen("operation.in","r",stdin);
	freopen("operation.out","w",stdout);
}

void swap(int &a,int &b)
{
	int t;
	t = a;a = b;b = t;
}

inline int max(int a,int b)
{
	return a > b ? a : b;
}

void res(int rt)
{
	swap(Tree[rt].maxL0,Tree[rt].maxL1);
	swap(Tree[rt].maxR0,Tree[rt].maxR1);
	swap(Tree[rt].Max0,Tree[rt].Max1);
	swap(Tree[rt].cnt0,Tree[rt].cnt1);
}

void pushup(int rt,int l,int r)
{
	int lc = rt << 1,rc = rt << 1 | 1;
	int m = (l + r) >> 1;
	Tree[rt].maxL0 = (Tree[lc].maxL0 == m - l + 1 ? Tree[lc].maxL0 + Tree[rc].maxL0 : Tree[lc].maxL0);
	Tree[rt].maxL1 = (Tree[lc].maxL1 == m - l + 1 ? Tree[lc].maxL1 + Tree[rc].maxL1 : Tree[lc].maxL1);
	Tree[rt].maxR0 = (Tree[rc].maxR0 == r - m ? Tree[lc].maxR0 + Tree[rc].maxR0 : Tree[rc].maxR0);
	Tree[rt].maxR1 = (Tree[rc].maxR1 == r - m ? Tree[lc].maxR1 + Tree[rc].maxR1 : Tree[rc].maxR1);
	Tree[rt].Max0 = max(Tree[lc].maxR0 + Tree[rc].maxL0,max(Tree[lc].Max0,Tree[rc].Max0));
	Tree[rt].Max1 = max(Tree[lc].maxR1 + Tree[rc].maxL1,max(Tree[lc].Max1,Tree[rc].Max1));
	Tree[rt].cnt0 = Tree[lc].cnt0 + Tree[rc].cnt0;
	Tree[rt].cnt1 = Tree[lc].cnt1 + Tree[rc].cnt1;
}

void pushdown(int rt,int lc,int rc,int nu)
{
	if(Tree[rt].cover != -1)
	{
		Tree[lc].cover = Tree[rc].cover = Tree[rt].cover;
		Tree[lc].maxL0 = Tree[lc].maxR0 = Tree[lc].Max0 = Tree[rt].cover == 0 ? nu - (nu >> 1) : 0;
		Tree[rc].maxL0 = Tree[rc].maxR0 = Tree[rc].Max0 = Tree[rt].cover == 0 ? (nu >> 1) : 0;
		Tree[lc].maxL1 = Tree[lc].maxR1 = Tree[lc].Max1 = Tree[rt].cover == 0 ? 0 : nu - (nu >> 1);
		Tree[rc].maxL1 = Tree[rc].maxR1 = Tree[rc].Max1 = Tree[rt].cover == 0 ? 0 : (nu >> 1);
		Tree[lc].cnt0 = Tree[rt].cover == 0 ? nu - (nu >> 1) : 0;
		Tree[rc].cnt0 = Tree[rt].cover == 0 ? (nu >> 1) : 0;
		Tree[lc].cnt1 = Tree[rt].cover == 1 ? nu - (nu >> 1) : 0;
		Tree[rc].cnt1 = Tree[rt].cover == 1 ? (nu >> 1) : 0;
		Tree[lc].reserve = Tree[rc].reserve = false;
		Tree[rt].cover = -1;
	}
	if(Tree[rt].reserve)
	{
		Tree[lc].reserve = !Tree[lc].reserve;
		Tree[rc].reserve = !Tree[rc].reserve;
		res(lc);res(rc);
		Tree[rt].reserve = false;
	}
}

void build(int l,int r,int rt)
{
	if(l == r)
	{
		int tmp;
		scanf("%d",&tmp);
		if(tmp == 0)
		{
			Tree[rt].maxL0 = Tree[rt].maxR0 = Tree[rt].Max0 = 1;
			Tree[rt].cnt0 = 1;
		}
		else
		{
			Tree[rt].maxL1 = Tree[rt].maxR1 = Tree[rt].Max1 = 1;
			Tree[rt].cnt1 = 1;
		}
		return;
	}
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
	pushup(rt,l,r);
}

void updata(int sc,int L,int R,int l,int r,int rt)
{
	if(L <= l && r <= R)
	{
		if(sc == 2)Tree[rt].reserve = !Tree[rt].reserve,res(rt);
		else
		{
			Tree[rt].reserve = false;
			Tree[rt].cover = sc;
			Tree[rt].maxL0 = Tree[rt].maxR0 = Tree[rt].Max0 = sc == 0 ? r - l + 1 : 0;
			Tree[rt].maxL1 = Tree[rt].maxR1 = Tree[rt].Max1 = sc == 1 ? r - l + 1 : 0;
			Tree[rt].cnt0 = sc == 0 ? r - l + 1 : 0;
			Tree[rt].cnt1 = sc == 1 ? r - l + 1 : 0;
		}
		return;
	}
	pushdown(rt,rt<<1,rt<<1|1,r-l+1);
	int m = (l + r) >> 1;
	if(L <= m)updata(sc,L,R,lson);
	if(R > m)updata(sc,L,R,rson);
	pushup(rt,l,r);
}

void maintain(tree lc,tree rc,int l,int r)
{
	int m = (l + r) >> 1;
	ans.maxL0 = (lc.maxL0 == m - l + 1 ? lc.maxL0 + rc.maxL0 : lc.maxL0);
	ans.maxL1 = (lc.maxL1 == m - l + 1 ? lc.maxL1 + rc.maxL1 : lc.maxL1);
	ans.maxR0 = (rc.maxR0 == r - m ? lc.maxR0 + rc.maxR0 : rc.maxR0);
	ans.maxR1 = (rc.maxR1 == r - m ? lc.maxR1 + rc.maxR1 : rc.maxR1);
	ans.Max0 = max(lc.maxR0 + rc.maxL0,max(lc.Max0,rc.Max0));
	ans.Max1 = max(lc.maxR1 + rc.maxL1,max(lc.Max1,rc.Max1));
	ans.cnt0 = lc.cnt0 + rc.cnt0;
	ans.cnt1 = lc.cnt1 + rc.cnt1;
}

tree query(int L,int R,int l,int r,int rt)
{
	if(L <= l && r <= R)return Tree[rt];
	pushdown(rt,rt<<1,rt<<1|1,r-l+1);
	int m = (l + r) >> 1;
	tree lc,rc;
	if(L <= m)lc = query(L,R,lson);
	if(R > m)rc = query(L,R,rson);
	maintain(lc,rc,l,r);
	return ans;
}

void readdata()
{
	scanf("%d%d",&n,&m);
	build(1,n,1);
	for(int i = 1;i <= m;i++)
	{
		int p,l,r;
		scanf("%d%d%d",&p,&l,&r);
		l++;r++;
		if(p <= 2)updata(p,l,r,1,n,1);
		if(p == 3)printf("%d\n",query(l,r,1,n,1).cnt1);
		if(p == 4)printf("%d\n",query(l,r,1,n,1).Max1);
	}
}

int main()
{
	init();
	readdata();
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值