这个题和 XOR的艺术 以及 [USACO08NOV]光开关Light Switching 非常相似,思路都是完全一样的
我们用线段树来维护区间内亮的灯的个数,lazy标记维护当前区间是否被反了一遍
这就是基本思路
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define mid ((l+r)>>1)
#define ls (x<<1)
#define rs ((x<<1)|1)
#define MAXN 100010
#define For(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
inline int read()
{
char c;bool t=0;int a=0;
while((c=getchar())==' '||c=='\n'||c=='\r');
if(c=='-'){t=1;c=getchar();}
while(isdigit(c)){a*=10;a+=(c-'0');c=getchar();}
return a*(t?-1:1);
}
int sum[MAXN*4],ans,n,m;
bool lazy[MAXN*4];
void down(int l,int r,int x)
{
sum[ls]=mid-l+1-sum[ls];
sum[rs]=r-mid-sum[rs];
lazy[ls]=!lazy[ls];
lazy[rs]=!lazy[rs];
lazy[x]=0;
}
void modify(int l,int r,int x,int ll,int rr)
{
if(ll<=l&&r<=rr)
{
sum[x]=r-l+1-sum[x];
lazy[x]=!lazy[x];
}
else
{
if(lazy[x])
down(l,r,x);
if(ll<=mid)
modify(l,mid,ls,ll,rr);
if(mid<rr)
modify(mid+1,r,rs,ll,rr);
sum[x]=sum[ls]+sum[rs];
}
}
void ask(int l,int r,int x,int ll,int rr)
{
if(ll<=l&&r<=rr)
{
ans+=sum[x];
}
else
{
if(lazy[x])
{
down(l,r,x);
sum[x]=sum[ls]+sum[rs];
}
if(ll<=mid)
ask(l,mid,ls,ll,rr);
if(mid<rr)
ask(mid+1,r,rs,ll,rr);
}
}
int main()
{
int tx,ty,tz;
n=read();m=read();
For(i,1,m)
{
tx=read();ty=read();tz=read();
if(tx)
{
ans=0;
ask(1,n,1,ty,tz);
printf("%d\n",ans);
}
else
{
modify(1,n,1,ty,tz);
}
}
return 0;
}