ABC341E 题解

看到 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;
}
posted @ 2024-02-18 14:53  Aurora_Borealis  阅读(13)  评论(0编辑  收藏  举报