P3870 [TJOI2009]开关
Posted five20
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3870 [TJOI2009]开关相关的知识,希望对你有一定的参考价值。
题目描述
现有N(2 ≤ N ≤ 100000)盏灯排成一排,从左到右依次编号为:1,2,......,N。然后依次执行M(1 ≤ M ≤ 100000)项操作,操作分为两种:第一种操作指定一个区间[a, b],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开),第二种操作是指定一个区间[a, b],要求你输出这个区间内有多少盏灯是打开的。灯在初始时都是关着的。
输入输出格式
输入格式:第一行有两个整数N和M,分别表示灯的数目和操作的数目。接下来有M行,每行有三个整数,依次为:c, a, b。其中c表示操作的种类,当c的值为0时,表示是第一种操作。当c的值为1时表示是第二种操作。a和b则分别表示了操作区间的左右边界(1 ≤ a ≤ b ≤ N)。
输出格式:每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。
输入输出样例
输入样例#1:
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
输出样例#1:
1
2
Solution:
本题裸的线段树模板~~。
对于每次修改取反,直接修改一下懒惰标记(改为$Xor\;1$),并对区间和取反(即$sum[rt]=(r-l+1)-sum[rt]$),意味着原来的$0$的个数就是修改后区间中的$1$的个数。
然后就是简单的区间修改区间求和拉~。
代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 using namespace std; 6 const int N=1e5+5; 7 int n,m,sum[N<<2],lazy[N<<2]; 8 il int gi(){ 9 int a=0;char x=getchar();bool f=0; 10 while((x<‘0‘||x>‘9‘)&&x!=‘-‘)x=getchar(); 11 if(x==‘-‘)x=getchar(),f=1; 12 while(x>=‘0‘&&x<=‘9‘)a=a*10+x-48,x=getchar(); 13 return f?-a:a; 14 } 15 il void pushup(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];} 16 il void pushdown(int rt,int k){ 17 if(lazy[rt]){ 18 lazy[rt<<1]^=1; 19 lazy[rt<<1|1]^=1; 20 sum[rt<<1]=(k-(k>>1))-sum[rt<<1]; 21 sum[rt<<1|1]=(k>>1)-sum[rt<<1|1]; 22 lazy[rt]=0; 23 } 24 } 25 il void update(int L,int R,int c,int l,int r,int rt){ 26 if(L<=l&&R>=r){lazy[rt]^=1;sum[rt]=(r-l+1)-sum[rt];return;} 27 pushdown(rt,r-l+1); 28 int m=l+r>>1; 29 if(L<=m)update(L,R,c,lson); 30 if(m<R)update(L,R,c,rson); 31 pushup(rt); 32 } 33 il int query(int L,int R,int l,int r,int rt){ 34 if(L<=l&&R>=r){return sum[rt];} 35 pushdown(rt,r-l+1); 36 int m=l+r>>1,ret=0; 37 if(L<=m)ret+=query(L,R,lson); 38 if(m<R)ret+=query(L,R,rson); 39 return ret; 40 } 41 int main(){ 42 n=gi(),m=gi(); 43 int x,y,z; 44 while(m--){ 45 x=gi(),y=gi(),z=gi(); 46 if(!x)update(y,z,1,1,n,1); 47 else printf("%d\n",query(y,z,1,n,1)); 48 } 49 return 0; 50 }
以上是关于P3870 [TJOI2009]开关的主要内容,如果未能解决你的问题,请参考以下文章