跳转至

01线段树

www.luogu.com.cn

例题 #1 [TJOI2009] 开关

题目描述

现有 \(n\) 盏灯排成一排,从左到右依次编号为:\(1\)\(2\),……,\(n\)。然后依次执行 \(m\) 项操作。

操作分为两种:

  1. 指定一个区间 \([a,b]\),然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开);

  2. 指定一个区间 \([a,b]\),要求你输出这个区间内有多少盏灯是打开的。

灯在初始时都是关着的。

输入格式

第一行有两个整数 \(n\)\(m\),分别表示灯的数目和操作的数目。

接下来有 \(m\) 行,每行有三个整数,依次为:\(c\)\(a\)\(b\)。其中 \(c\) 表示操作的种类。

  • \(c\) 的值为 \(0\) 时,表示是第一种操作。

  • \(c\) 的值为 \(1\) 时,表示是第二种操作。

\(a\)\(b\) 则分别表示了操作区间的左右边界。

输出格式

每当遇到第二种操作时,输出一行,包含一个整数,表示此时在查询的区间中打开的灯的数目。

对于全部的测试点,保证 \(2\le n\le 10^5\)\(1\le m\le 10^5\)\(1\le a,b\le n\)\(c\in\{0,1\}\)


线段树维护01翻转tag。

/*
Edit by Ntsc.
*/

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define pii pair<int, int>
#define pf first
#define ps second

#define rd read()
#define ot write
#define nl putchar('\n')
inline int rd{
    int xx=0,ff=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') ff=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') xx=xx*10+(ch-'0'),ch=getchar();
    return xx*ff;
}
inline void write(int out){
    if(out<0) putchar('-'),out=-out;
    if(out>9) write(out/10);
    putchar(out%10+'0');
}

const int N=4e5+5;
const int M=5e4+5;
const int INF=2e18+5;
const int MOD=1e9+7;
const int BASE=17737;
bool f1;
int m;
int n,tr[N],tag[N];

bool f2;

void pushup(int x){
    tr[x]=tr[x<<1]+tr[x<<1|1];
}
void addtag(int x,int l,int r){
    tr[x]=r-l+1-tr[x];
    tag[x]^=1;
}
void pushdown(int x,int l,int r){
    int mid=l+r>>1;
    if(!tag[x])return ;
    addtag(x<<1,l,mid);
    addtag(x<<1|1,mid+1,r);
    tag[x]=0;
}
void change(int x,int l,int r,int pl,int pr){
    if(l>=pl&&r<=pr){
        addtag(x,l,r);
//      cerr<<"ck";
        return ;
    }
    pushdown(x,l,r);
    int mid=l+r>>1;
    if(pl<=mid)change(x<<1,l,mid,pl,pr);
    if(pr>mid)change(x<<1|1,mid+1,r,pl,pr);
    pushup(x);
}

int query(int x,int l,int r,int pl,int pr,int tg){
    if(l>=pl&&r<=pr){
        return tr[x];
    }
    pushdown(x,l,r);
    int res=0;
    int mid=l+r>>1;
    if(pl<=mid)res+=query(x<<1,l,mid,pl,pr,tg^tag[x]);
    if(pr>mid)res+=query(x<<1|1,mid+1,r,pl,pr,tg^tag[x]);
    return res;
}
signed main(){
    n=rd,m=rd;
    for(int i=1;i<=m;i++){
        int op=rd;
        int a=rd,b=rd;
        if(op){
            cout<<query(1,1,n,a,b,0)<<endl;
        }else{
            change(1,1,n,a,b);
        }
    }
    return 0;
}
/*


*/