看题面可以目测得出本题要求对01区间进行区间修改和查询。
查询区间和,就直接维护区间和。在修改时,就用总灯数(长度)减去当前开着的灯数(当前区间和)作为新的答案。
考虑修改两次相当于没修改,所以(lazytag)就累计操作数,如果是偶数则不用更新呢,奇数反之。
其余部分与线段树模板基本相同。
#include<iostream>
#define int long long
using namespace std;
const int MAXN=100005;
int n,m,a[MAXN],seg[MAXN<<2],tag[MAXN<<2];
int u,v,w;
inline void upd(int x)
{
seg[x]=seg[x<<1]+seg[x<<1|1];
}
inline int push_down(int x,int l,int r)
{
tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];
int mid=(l+r)>>1;
if(tag[x]&1)
{
seg[x<<1]=(mid-l+1)-seg[x<<1];
seg[x<<1|1]=(r-mid)-seg[x<<1|1];
}
tag[x]=0;
}
inline int query(int x,int l,int r,int ql,int qr)
{
int temp=0,mid=(l+r)>>1;
if(ql<=l&&r<=qr) return seg[x];
push_down(x,l,r);
if(ql<=mid) temp+=query(x<<1,l,mid,ql,qr);
if(mid<qr) temp+=query(x<<1|1,mid+1,r,ql,qr);
return temp;
}
inline void modify(int x,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
seg[x]=(r-l+1)-seg[x];
tag[x]+=1;
} else {
push_down(x,l,r);
int mid=(l+r)>>1;
if(ql<=mid) modify(x<<1,l,mid,ql,qr);
if(mid<qr) modify(x<<1|1,mid+1,r,ql,qr);
upd(x);
}
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>w;
if(u==0)
modify(1,1,n,v,w);
else
cout<<query(1,1,n,v,w)<<"
";
}
return 0;
}