【线段树】Bzoj1230 [Usaco2008 Nov]lites 开关灯

Description

Farmer John尝试通过和奶牛们玩益智玩具来保持他的奶牛们思维敏捷. 其中一个大型玩具是牛栏中的灯. N (2 <= N <= 100,000) 头奶牛中的每一头被连续的编号为1..N, 站在一个彩色的灯下面.刚到傍晚的时候, 所有的灯都是关闭的. 奶牛们通过N个按钮来控制灯的开关; 按第i个按钮可以改变第i个灯的状态.奶牛们执行M (1 <= M <= 100,000)条指令, 每个指令都是两个整数中的一个(0 <= 指令号 <= 1). 第1种指令(用0表示)包含两个数字S_i和E_i (1 <= S_i <= E_i <= N), 它们表示起始开关和终止开关. 奶牛们只需要把从S_i到E_i之间的按钮都按一次, 就可以完成这个指令. 第2种指令(用1表示)同样包含两个数字S_i和E_i (1 <= S_i <= E_i <= N), 不过这种指令是询问从S_i到E_i之间的灯有多少是亮着的. 帮助FJ确保他的奶牛们可以得到正确的答案.

 

Solution

记录两个量tag和sum,用lazy维护。

刷水+复习线段树。

 

Code

lazy处理祖先对后代的方法有两种,递归时记录或每次都pushdown,前者常数小但后者更无脑不容易错。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=4e5+5;
 5 
 6 int tag[maxn],sum[maxn];
 7 int n,m;
 8 int x,p,q,ret;
 9 
10 int pushup(int o){
11     sum[o]=sum[o*2]+sum[o*2+1];
12 }
13 
14 int pushdown(int o,int l,int r){
15     int mid=(l+r)>>1;
16     tag[o]=0;
17     tag[o*2]^=1,tag[o*2+1]^=1;
18     sum[o*2]=(mid-l+1-sum[o*2]);
19     sum[o*2+1]=(r-mid-sum[o*2+1]);
20 }
21 
22 void add(int o,int l,int r){
23     if(p<=l&&r<=q){
24         tag[o]^=1;
25         sum[o]=(r-l+1-sum[o]);
26         return;
27     }
28     if(tag[o]) pushdown(o,l,r);
29     int mid=(l+r)>>1;
30     if(p<=mid) add(o*2,l,mid);
31     if(q>mid) add(o*2+1,mid+1,r);
32     pushup(o);
33 }
34 
35 void ask(int o,int l,int r,int k){
36     if(p<=l&&r<=q){
37         if(!k) ret+=sum[o];
38         else ret+=(r-l+1-sum[o]);
39         return;
40     }
41     int mid=(l+r)>>1;
42     if(p<=mid) ask(o*2,l,mid,k^tag[o]);
43     if(q>mid) ask(o*2+1,mid+1,r,k^tag[o]);
44 }
45 
46 int main(){
47     scanf("%d%d",&n,&m);
48     for(int i=1;i<=m;i++){
49         scanf("%d%d%d",&x,&p,&q);
50         if(x==0) add(1,1,n);
51         else{
52             ret=0;
53             ask(1,1,n,0);
54             printf("%d\n",ret);
55         }
56     }
57     return 0;
58 }

每次都pushdown代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=4e5+5;
 5 
 6 int tag[maxn],sum[maxn];
 7 int n,m;
 8 int x,p,q,ret;
 9 
10 int pushup(int o){
11     sum[o]=sum[o*2]+sum[o*2+1];
12 }
13 
14 int pushdown(int o,int l,int r){
15     int mid=(l+r)>>1;
16     tag[o]=0;
17     tag[o*2]^=1,tag[o*2+1]^=1;
18     sum[o*2]=(mid-l+1-sum[o*2]);
19     sum[o*2+1]=(r-mid-sum[o*2+1]);
20 }
21 
22 void add(int o,int l,int r){
23     if(p<=l&&r<=q){
24         tag[o]^=1;
25         sum[o]=(r-l+1-sum[o]);
26         return;
27     }
28     if(tag[o]) pushdown(o,l,r);
29     int mid=(l+r)>>1;
30     if(p<=mid) add(o*2,l,mid);
31     if(q>mid) add(o*2+1,mid+1,r);
32     pushup(o);
33 }
34 
35 void ask(int o,int l,int r){
36     if(p<=l&&r<=q){
37         ret+=sum[o];
38         return;
39     }
40     if(tag[o]) pushdown(o,l,r);
41     int mid=(l+r)>>1;
42     if(p<=mid) ask(o*2,l,mid);
43     if(q>mid) ask(o*2+1,mid+1,r);
44     pushup(o);
45 }
46 
47 int main(){
48     scanf("%d%d",&n,&m);
49     for(int i=1;i<=m;i++){
50         scanf("%d%d%d",&x,&p,&q);
51         if(x==0) add(1,1,n);
52         else{
53             ret=0;
54             ask(1,1,n);
55             printf("%d\n",ret);
56         }
57     }
58     return 0;
59 }
View Code

 

posted @ 2015-06-07 18:22  CyanNode  阅读(216)  评论(0编辑  收藏  举报