题目描述
现有N(2 ≤ N ≤ 100000)盏灯排成一排,从左到右依次编号为:1,2,......,N。然后依次执行M(1 ≤ M ≤ 100000)项操作,操作分为两种:第一种操作指定一个区间[a, b],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开),第二种操作是指定一个区间[a, b],要求你输出这个区间内有多少盏灯是打开的。灯在初始时都是关着的。
输入输出格式
输入格式:
第一行有两个整数N和M,分别表示灯的数目和操作的数目。接下来有M行,每行有三个整数,依次为:c, a, b。其中c表示操作的种类,当c的值为0时,表示是第一种操作。当c的值为1时表示是第二种操作。a和b则分别表示了操作区间的左右边界(1 ≤ a ≤ b ≤ N)。
输出格式:
每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。
输入输出样例
输入样例#1:
复制
4 5 0 1 2 0 2 4 1 2 3 0 2 4 1 1 4
输出样例#1:
复制
View Code
1 2
可以用异或 见代码
因为一开始亮的灯数为0 所以不用build
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define pb push_back #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) // #define inf 0x3f3f3f3f #define lson l,m,pos<<1 #define rson m+1,r,pos<<1|1 const int N=100000+5; ll sum[N<<2],col[N<<2]; void up(int pos) { sum[pos]=sum[pos<<1]+sum[pos<<1|1]; } void down(int pos,int m) { if(col[pos]) { col[pos<<1]^=1;//每个下传懒标记进行异或 因为负负得正 col[pos<<1|1]^=1; sum[pos<<1]=(m-(m>>1))-sum[pos<<1];//正常修改 sum[pos<<1|1]=(m>>1)-sum[pos<<1|1]; col[pos]=0; } } void update(int L,int R,int l,int r,int pos) { if(L<=l&&r<=R) { col[pos]^=1;//不能改成1! sum[pos]=r-l+1-sum[pos]; return ; } int m=(l+r)>>1; down(pos,r-l+1); if(L<=m) update(L,R,lson); if(R>m) update(L,R,rson); up(pos); } int query(int L,int R,int l,int r,int pos)//正常讯问 { if(L<=l&&r<=R) return sum[pos]; down(pos,r-l+1); int ans=0; int m=(l+r)>>1; if(L<=m)ans+=query(L,R,lson); if(R>m)ans+=query(L,R,rson); return ans; } int main() { int n,m; RII(n,m); rep(i,1,m) { int a,b,c;RIII(a,b,c); if(a) cout<<query(b,c,1,n,1)<<endl; else update(b,c,1,n,1); } return 0; }