洛谷的进阶版书籍中只给出了make_tag的写法,今天刚学习了线段树,感觉很有意思,所以按照书中模版写了一个完整版,需要注意的是在pushdown中由于进行两次操作等的开关情况并不会变,所以在pushdown时要判断一下lazy-tag的奇偶
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int a[MAXN],w[MAXN*4],lzy[MAXN*4],n,m;
void pushup(const int u){
w[u]=w[u*2]+w[u*2+1];
}
void build(const int u,int l,int r){
if(l==r){
w[u]=a[l];
return;
}
int mid=(l+r)>>1;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
pushup(u);
}
bool inrange(int L,int R,int l,int r){
return l<=L && r>=R;
}
bool outofrange(int L,int R,int l,int r){
return L>r || R<l;
}
void maketag(int u,int l,int r){
lzy[u]^=1;
w[u]=r-l+1-w[u];
}
void pushdown(int u,int l,int r){
int mid=(l+r)>>1;
if(lzy[u]) maketag(u*2,l,mid);
if(lzy[u]) maketag(u*2+1,mid+1,r);
lzy[u]=0;
}
int query(int u,int L,int R,int l,int r){
if(inrange(L,R,l,r)) return w[u];
else if(!outofrange(L,R,l,r)){
int mid=(L+R)>>1;
pushdown(u,L,R);
return query(u*2,L,mid,l,r)+query(u*2+1,mid+1,R,l,r);
}
else return 0;
}
void update(int u,int L,int R,int l,int r){
if(inrange(L,R,l,r)){
maketag(u,L,R);
}
else if(!outofrange(L,R,l,r)){
int mid=(L+R)>>1;
pushdown(u,L,R);
update(u*2,L,mid,l,r);
update(u*2+1,mid+1,R,l,r);
pushup(u);
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
build(1,1,n);
while(m--){
int opt,x,y;
cin>>opt>>x>>y;
if(opt==0) update(1,1,n,x,y);
else cout<<query(1,1,n,x,y)<<endl;
}
return 0;
}