看到 01 串的反转考虑维护异或差分序列 \(s_i=a_i \oplus a_{i-1}\)。
这样区间反转就变成了单点修改。
然后考虑怎么查询:
若一个区间 \([l,r]\) 是好区间,那么对于 \(i \in [l+1,r]\) 一定存在 \(s_i=1\)。所以我们可以查询区间和来判断是否为好区间。
使用线段树维护区间和即可,单点修改区间查询,复杂度 \(O(m\log n)\)。注意特判边界情况。
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define vi vector<int>
#define pb push_back
#define imp map<int,int>
#define debug printf("debug\n")
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
using namespace std;
const int N=5e5+5;
int n,q,a[N],s[N],sum[N<<2];
void pushup(int p){
sum[p]=sum[ls(p)]+sum[rs(p)];
}
void build(int p,int l,int r){
if(l==r){
sum[p]=a[l]^a[l-1];
return;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
pushup(p);
}
void change(int p,int x,int l,int r){
if(l==r){
sum[p]^=1;
return;
}
int mid=(l+r)>>1;
if(x<=mid) change(ls(p),x,l,mid);
else change(rs(p),x,mid+1,r);
pushup(p);
}
int query(int p,int x,int y,int l,int r){
if(x<=l&&r<=y) return sum[p];
int mid=(l+r)>>1;
int ans=0;
if(x<=mid) ans+=query(ls(p),x,y,l,mid);
if(mid+1<=y) ans+=query(rs(p),x,y,mid+1,r);
return ans;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
char c;
cin>>c;
a[i]=c-'0';
}
build(1,1,n);
while(q--){
int x,y,op;
scanf("%d%d%d",&op,&x,&y);
if(op==1){
change(1,x,1,n);
if(y<n) change(1,y+1,1,n);
}else{
if(x==y){
printf("Yes\n");
continue;
}
int num=query(1,x+1,y,1,n);
if(num==(y-x)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
标签:ABC341E,int,题解,mid,long,build,区间,define
From: https://www.cnblogs.com/victoryang-not-found/p/18019319