P3870 [TJOI2009]开关(线段树xor修改)

题目创送门

简述题意

给出一颗01线段树,对其区间进行xor操作,并查询区间中1的个数


思路

最开始想用线段树来记录一个区间是否被xor过,再加上区间长度,后来发现不行,以为在一个区间可能会存在不同xor过的点。然后又想到直接单点查询,才发现复杂度直接O(nm),不可做。
于是改变思路,用平常思维来写,用sum表示区间和,想了很久怎么更新其值,后来想到,xor一个区间。更新区间只需要用区间长度减去原区间值就好了。lazy的维护用原值xor,因为两次xor就相当于还原就好了。


代码

#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn=1e5+10;
int lazy[maxn<<2],sum[maxn<<2];
int res=0;
int n,m;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void pushup(int rt)
{
	sum[rt]=sum[lson]+sum[rson];
}
inline void pushdown(int rt,int m)
{
	if(lazy[rt])
	{
		sum[lson]=m-(m>>1)-sum[lson];
		sum[rson]=(m>>1)-sum[rson];
		lazy[lson]^=1;
		lazy[rson]^=1;
		lazy[rt]=0;
	}
}
void update(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		lazy[rt]^=1;
		sum[rt]=r-l+1-sum[rt];
		return;
	}
	pushdown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m)
	update(L,R,l,m,lson);
	if(m<R)
	update(L,R,m+1,r,rson);
	pushup(rt);
}
inline void query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		res+=sum[rt];
		return;
	}
	pushdown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m)
	query(L,R,l,m,lson);
	if(m<R)
	query(L,R,m+1,r,rson);
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		int op=read();
		if(op==0)
		{
			int x=read(),y=read();
			update(x,y,1,n,1);
		}
		if(op==1)
		{
			int x=read(),y=read();
			res=0;
			query(x,y,1,n,1);
			printf("%d\n",res);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值