洛谷3870 开关(线段树)

Build后忘push_up简直有毒

【题目分析】

题意还是很明显的,支持区间取反,区间查询。

所以我们线段树的sum数组开成二维的,第一维记录关的灯的数量,第二维记录开着的灯的数量。

push_down的lazy标记就swap一下0和1的个数。

查询时返回区间1的sum即可。

【代码~】

#include
using namespace std;
const int MAXN=1e5+10;

int laz[MAXN<<2];
int zt[MAXN<<2],sum[MAXN<<2][2];
int n,q;

void push_up(int root)
{
	sum[root][0]=sum[root<<1][0]+sum[root<<1|1][0];
	sum[root][1]=sum[root<<1][1]+sum[root<<1|1][1];
}

void push_down(int root)
{
	if(laz[root])
	{
		swap(sum[root<<1][0],sum[root<<1][1]);
		swap(sum[root<<1|1][0],sum[root<<1|1][1]);
		laz[root<<1]^=1;
		laz[root<<1|1]^=1;
		laz[root]=0;
	}
}

void build(int root,int l,int r)
{
	if(l==r)
	{
		sum[root][0]=1;
		return ;
	}
	int mid=l+r>>1;
	build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
	push_up(root);
}

void update(int root,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)
	{
		laz[root]^=1;
		swap(sum[root][0],sum[root][1]);
		return ;
	}
	push_down(root);
	int mid=l+r>>1;
	if(L<=mid)
	  update(root<<1,l,mid,L,R);
	if(R>mid)
	  update(root<<1|1,mid+1,r,L,R);
	push_up(root);
}

int query(int root,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)
	  return sum[root][1];
	int ret=0,mid=l+r>>1;
	push_down(root);
	if(L<=mid)
	  ret+=query(root<<1,l,mid,L,R);
	if(R>mid)
	  ret+=query(root<<1|1,mid+1,r,L,R);
	return ret;
}

int main()
{
	scanf("%d%d",&n,&q);
	build(1,1,n);
	while(q--)
	{
		int cz,l,r;
		scanf("%d%d%d",&cz,&l,&r);
		if(cz==0)
		  update(1,1,n,l,r);
		else
		  printf("%d\n",query(1,1,n,l,r));
	}
	return 0;
}

 

转载于:https://www.cnblogs.com/Ishtar/p/10010778.html

你可能感兴趣的:(洛谷3870 开关(线段树))