b_lg_XOR的艺术 & 开关(tag标记是否点亮)

现有n盏灯排成一排,有两种操作,一种是对区间中的灯的开关状态进行反转,一种是统计区间中开着的灯的数量(n<=1e5)

思路
tag[k]有两种状态:

  • 0:表示线段树中结点k自身及其所管控的子树的灯的状态为关闭
  • 1:表示线段树中结点k自身及其所管控的子树的灯的状态为点亮

在计算的时候如果tag[k]为0,则表示他被熄灭了,所以子树也是熄灭的,故push_down可以提前返回了

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,a[N<<2],tag[N<<2];
char s[N];
void p_up(int k) {
    a[k]=a[k<<1]+a[k<<1|1];
}
void p_down(int l, int r, int k) {
    if(tag[k]==0) return;
    int m=l+r>>1;
    a[k<<1]=(m-l+1)-a[k<<1];
    a[k<<1|1]=(r-m)-a[k<<1|1];
    tag[k]^=1, tag[k<<1]^=1, tag[k<<1|1]^=1;
}
void build(int l, int r, int k) {
    if (l==r) {
        a[k]=tag[k]=s[l]=='1';
        return;
    }
    int m=l+r>>1;
    build(l,m,k<<1);
    build(m+1,r,k<<1|1);
    p_up(k);
}
void upd(int ql, int qr, int l, int r, int k) {
    if (ql<=l && r<=qr) {
        a[k]=(r-l+1)-a[k]; //[l,r]中灯的总数量,a[k]为[l,r]中亮着的灯的数量
        tag[k]^=1;
        return;
    }
    p_down(l,r,k);
    int m=l+r>>1;
    if (m>=ql) upd(ql,qr,l,m,k<<1);
    if (m<qr)  upd(ql,qr,m+1,r,k<<1|1);
    p_up(k);
}
int ask(int ql, int qr, int l, int r, int k) {
    if (ql<=l && r<=qr)
        return a[k];
    p_down(l,r,k);
    int m=l+r>>1, ans=0;
    if (m>=ql) ans+=ask(ql,qr,l,m,k<<1);
    if (m<qr)  ans+=ask(ql,qr,m+1,r,k<<1|1);
    return ans;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 
    cin>>n>>m>>s+1;
    build(1,n,1);
    for (int i=0; i<m; i++) {
        int t,l,r; cin>>t>>l>>r;
        if (t==0) upd(l,r,1,n,1);
        else cout<<ask(l,r,1,n,1)<<'
';
    }    
    return 0;
}
原文地址:https://www.cnblogs.com/wdt1/p/13920947.html