【TJOI 2009】开关

【题目】

传送门

题目描述:

现有 n n 2 2 n n 100000 100000 )盏灯排成一排,从左到右依次编号为: 1 1 2 2 ,…, n n 。然后依次执行 m m 1 1 m m 100000 100000 )项操作,操作分为两种:第一种操作指定一个区间 [ a , b a, b ] ,然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开),第二种操作是指定一个区间 [ a , b a, b ] ,要求你输出这个区间内有多少盏灯是打开的。灯在初始时都是关着的。

输入格式:

第一行有两个整数 n n m m ,分别表示灯的数目和操作的数目。
接下来有 m m 行,每行有三个整数,依次为: c , a , b c, a, b 。其中 c c 表示操作的种类,当 c c 的值为 0 0 时,表示是第一种操作。当 c c 的值为 1 1 时表示是第二种操作。 a a b b 则分别表示了操作区间的左右边界( 1 1 a a b b n n )。

输出格式:

每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。

样例数据:

输入
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4

输出
1
2


【分析】

题解:线段树

假设 0 0 表示关着的灯, 1 1 表示开着的灯

我们用两个数组 s u m x , 0 sum_{x,0} 表示 x x 0 0 的个数, s u m x , 1 sum_{x,1} 表示 x x 1 1 的个数

然后只用累计取反操作的次数(累加或异或都可以),若要取反,则交换 s u m x , 0 sum_{x,0} s u m x , 1 sum_{x,1} 即可

剩下的就是基础的线段树操作了

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
int sum[N<<2][2],mark[N<<2];
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);
	sum[root][0]=sum[root<<1][0]+sum[root<<1|1][0];
}
void pushdown(int root)
{
	swap(sum[root<<1][0],sum[root<<1][1]);
	swap(sum[root<<1|1][0],sum[root<<1|1][1]);
	mark[root<<1]^=1,mark[root<<1|1]^=1,mark[root]=0;
}
void modify(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	{
		mark[root]^=1;
		swap(sum[root][0],sum[root][1]);
		return;
	}
	int mid=(l+r)>>1;
	if(mark[root])  pushdown(root);
	if(x<=mid)  modify(root<<1,l,mid,x,y);
	if(y>mid)  modify(root<<1|1,mid+1,r,x,y);
	sum[root][0]=sum[root<<1][0]+sum[root<<1|1][0];
	sum[root][1]=sum[root<<1][1]+sum[root<<1|1][1];
}
int query(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	  return sum[root][1];
	int ans=0,mid=(l+r)>>1;
	if(mark[root])  pushdown(root);
	if(x<=mid)  ans+=query(root<<1,l,mid,x,y);
	if(y>mid)  ans+=query(root<<1|1,mid+1,r,x,y);
	return ans;
}
int main()
{
	int n,m,i,s,x,y;
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d",&s,&x,&y);
		if(s==0)  modify(1,1,n,x,y);
		if(s==1)  printf("%d\n",query(1,1,n,x,y));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/83144342
今日推荐