HDU3397 Sequence operation 区间修改,区间异或,区间合并,线段树经典题

本文介绍了一种使用线段树实现区间修改、区间异或及区间合并的方法,并提供了详细的C++代码实现。通过构建线段树,可以高效地处理区间内的操作,包括更新指定区间的值或对区间进行异或运算。
分别记录下0和1的连续段,异或就是把01值交换,不难,想清楚再敲
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls (rt<<1)
#define rs (rt<<1|1)
const int M = 100001;

int n,d;
int Xor[M<<2];
int cover[M<<2];
int lpa[M<<2][2],rpa[M<<2][2],mpa[M<<2][2],num[M<<2][2];
int L,R,op;

int max(int a, int b) { return a>b?a:b; }
int min(int a, int b) { return a<b?a:b; }
void swap(int &a, int &b) { int temp = a; a = b; b = temp; }

void Or(int rt)
{
	if(cover[rt] != -1)
	{
		cover[rt] ^= 1;
	}
	else
	{
		Xor[rt] ^= 1;
	}
}

void SWAP(int rt)
{
	swap(lpa[rt][0], lpa[rt][1]);
	swap(rpa[rt][0], rpa[rt][1]);
	swap(mpa[rt][0], mpa[rt][1]);
	swap(num[rt][0], num[rt][1]);
}

void pushup(int m, int len, int rt)
{
	for(int i=0; i<2; i++)
	{
		lpa[rt][i] = lpa[ls][i];
		rpa[rt][i] = rpa[rs][i];
		if(lpa[rt][i] == len-(len>>1)) lpa[rt][i] += lpa[rs][i];
		if(rpa[rt][i] == (len>>1)) rpa[rt][i] += rpa[ls][i];
		mpa[rt][i] = rpa[ls][i] + lpa[rs][i];
		mpa[rt][i] = max(mpa[rt][i], max(mpa[ls][i], mpa[rs][i]));
		mpa[rt][i] = max(mpa[rt][i], max(lpa[rt][i], rpa[rt][i]));
		num[rt][i] = num[ls][i] + num[rs][i];
	}
	if(cover[ls]!=-1 && cover[ls]==cover[rs]) cover[rt] = cover[ls];
	else cover[rt] = -1;
}

void pushdown(int m, int len, int rt)
{
	if(cover[rt] != -1)
	{
		d = cover[rt];
		lpa[ls][d] = rpa[ls][d] = mpa[ls][d] = num[ls][d] = len-(len>>1);
		lpa[ls][!d] = rpa[ls][!d] = mpa[ls][!d] = num[ls][!d] = 0;
		cover[ls] = cover[rs] = d;
		Xor[ls] = Xor[rs] = 0;
		lpa[rs][d] = rpa[rs][d] = mpa[rs][d] = num[rs][d] = (len>>1);
		lpa[rs][!d] = rpa[rs][!d] = mpa[rs][!d] = num[rs][!d] = 0;
	}
	else if(Xor[rt])
	{
		Or(ls);
		SWAP(ls);
		Or(rs);
		SWAP(rs);
	}
	cover[rt] = -1;
	Xor[rt] = 0;
}

void build(int l, int r, int rt)
{
	Xor[rt] = 0;
	if(l == r)
	{
		scanf("%d", &d);
		cover[rt] = d;
		lpa[rt][d] = rpa[rt][d] = mpa[rt][d] = num[rt][d] = 1;
		lpa[rt][!d] = rpa[rt][!d] = mpa[rt][!d] = num[rt][!d] = 0;
	}
	else
	{
		int m = (l+r)>>1;
		build(lson);
		build(rson);
		pushup(m,r-l+1,rt);
	}
}

void update(int l, int r, int rt)
{
	if(L<=l && r<=R)
	{
		if(op <= 1)
		{
			Xor[rt] = 0;
			cover[rt] = op;
			lpa[rt][op] = rpa[rt][op] = mpa[rt][op] = num[rt][op] = r-l+1;
			lpa[rt][!op] = rpa[rt][!op] = mpa[rt][!op] = num[rt][!op] = 0;
		}
		else
		{
			SWAP(rt);
			Or(rt);
		}
	}
	else
	{
		int m = (l+r)>>1;
		pushdown(m,r-l+1,rt);
		if(L <= m) update(lson);
		if(m <  R) update(rson);
		pushup(m,r-l+1,rt);
	}
}

int query(int l, int r, int rt)
{
	if(L<=l && r<=R)
	{
		if(op == 3) return num[rt][1];
		else return mpa[rt][1];
	}
	else
	{
		int m = (l+r)>>1;
		pushdown(m,r-l+1,rt);
		if(op == 3)
		{
			int ans = 0;
			if(L <= m) ans = query(lson);
			if(m <  R) ans += query(rson);
			return ans;
		}
		else
		{
			int ans = min(rpa[ls][1],m-L+1) + min(lpa[rs][1],R-m);
			if(L <= m) ans = max(ans, query(lson));
			if(m <  R) ans = max(ans, query(rson));
			return ans;
		}
	}
}

int main()
{
	int m;
	int cas;
	scanf("%d", &cas);
	while(cas--)
	{
		scanf("%d%d", &n, &m);
		build(0,n-1,1);
		while(m--)
		{
			scanf("%d%d%d", &op, &L, &R);
			if(op >= 3) printf("%d\n", query(0,n-1,1));
			else update(0,n-1,1);
		}
	}
	return 0;
}

区间修改,区间异或,区间合并,线段树经典题
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值