题目链接
题意:
给你一个全为01的数组,有两个操作,一个是让区间变成全部异或,另一个是让全部区间求和。
思路:
线段树
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=5e5+5;
const int inf=0x3f3f3f3f;
const int mod=99999997;
int n,m,p,l,r,a[N];
char s[N];
int add[N<<2],sum[N<<2];
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void bulid(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=a[l];
return ;
}
int mid=(l+r)>>1;
bulid(l,mid,rt<<1);
bulid(mid+1,r,rt<<1|1);
pushup(rt);
}
void pushdown(int rt,int len)
{
if(add[rt])
{
add[rt<<1]^=1;
add[rt<<1|1]^=1;
sum[rt<<1]=(len-(len>>1))-sum[rt<<1];
sum[rt<<1|1]=(len>>1)-sum[rt<<1|1];
add[rt]=0;
}
}
int query(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
return sum[rt];
}
pushdown(rt,r-l+1);
int mid=(r+l)>>1,res=0;
if(L<=mid) res+=query(L,R,l,mid,rt<<1);
if(mid+1<=R) res+=query(L,R,mid+1,r,rt<<1|1);
return res;
}
void update(int L,int R,int l,int r,int rt)
{
pushdown(rt,r-l+1);
if(l>=L&&r<=R)
{
add[rt]^=1;//这里是和普通的修改线段树不同的地方
sum[rt]=r-l+1-sum[rt];
return ;
}
int mid=(l+r)>>1;
if(L<=mid) update(L,R,l,mid,rt<<1);
if(mid+1<=R) update(L,R,mid+1,r,rt<<1|1);
pushup(rt);
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
}
for(int i=1;i<=n;i++)
{
a[i]=s[i]-'0';
}
bulid(1,n,1);
for(int i=1;i<=m;i++)
{
cin>>p>>l>>r;
if(p==0)
{
update(l,r,1,n,1);
}
if(p==1)
{
cout<<query(l,r,1,n,1)<<endl;
}
}
return 0;
}