【题目】
题目描述:
现有 n n n( 2 2 2 ≤ n n n ≤ 100000 100000 100000)盏灯排成一排,从左到右依次编号为: 1 1 1, 2 2 2,…, n n n。然后依次执行 m m m( 1 1 1 ≤ m m m ≤ 100000 100000 100000)项操作,操作分为两种:第一种操作指定一个区间 [ a , b a, b a,b ] ,然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开),第二种操作是指定一个区间 [ a , b a, b a,b ] ,要求你输出这个区间内有多少盏灯是打开的。灯在初始时都是关着的。
输入格式:
第一行有两个整数
n
n
n 和
m
m
m ,分别表示灯的数目和操作的数目。
接下来有
m
m
m 行,每行有三个整数,依次为:
c
,
a
,
b
c, a, b
c,a,b。其中
c
c
c 表示操作的种类,当
c
c
c 的值为
0
0
0 时,表示是第一种操作。当
c
c
c 的值为
1
1
1 时表示是第二种操作。
a
a
a 和
b
b
b 则分别表示了操作区间的左右边界(
1
1
1 ≤
a
a
a ≤
b
b
b ≤
n
n
n)。
输出格式:
每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。
样例数据:
输入
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
输出
1
2
【分析】
题解:线段树
假设 0 0 0 表示关着的灯, 1 1 1 表示开着的灯
我们用两个数组 s u m x , 0 sum_{x,0} sumx,0 表示 x x x 中 0 0 0 的个数, s u m x , 1 sum_{x,1} sumx,1 表示 x x x 中 1 1 1 的个数
然后只用累计取反操作的次数(累加或异或都可以),若要取反,则交换 s u m x , 0 sum_{x,0} sumx,0 和 s u m x , 1 sum_{x,1} sumx,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;
}