【线段树】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 }

时间: 2024-12-21 21:58:38

【线段树】Bzoj1230 [Usaco2008 Nov]lites 开关灯的相关文章

bzoj1230 [Usaco2008 Nov]lites 开关灯

1230: [Usaco2008 Nov]lites 开关灯 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1615  Solved: 847[Submit][Status][Discuss] Description Farmer John尝试通过和奶牛们玩益智玩具来保持他的奶牛们思维敏捷. 其中一个大型玩具是牛栏中的灯. N (2 <= N <= 100,000) 头奶牛中的每一头被连续的编号为1..N, 站在一个彩色的灯下面.刚到傍晚的时候

BZOJ 1230: [Usaco2008 Nov]lites 开关灯( 线段树 )

线段树.. --------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #define clr( x

1230: [Usaco2008 Nov]lites 开关灯

1230: [Usaco2008 Nov]lites 开关灯 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1162  Solved: 589[Submit][Status] Description Farmer John尝试通过和奶牛们玩益智玩具来保持他的奶牛们思维敏捷. 其中一个大型玩具是牛栏中的灯. N (2 <= N <= 100,000) 头奶牛中的每一头被连续的编号为1..N, 站在一个彩色的灯下面.刚到傍晚的时候, 所有的灯都是关

B1230 [Usaco2008 Nov]lites 开关灯 线段树

就是线段树维护异或和.之前我线段树区间修改down都是修改当前区间,结果debug出不来,改成每次向下了. 题干: Description Farmer John尝试通过和奶牛们玩益智玩具来保持他的奶牛们思维敏捷. 其中一个大型玩具是牛栏中的灯. N (2 <= N <= 100,000) 头奶牛中的每一头被连续的编号为1..N, 站在一个彩色的灯下面.刚到傍晚的时候, 所有的灯都是关闭的. 奶牛们通过N个按钮来控制灯的开关; 按第i个按钮可以改变第i个灯的状态.奶牛们执行M (1 <=

P1230: [Usaco2008 Nov]lites 开关灯

嗯嗯,这是一道线段树的题,询问区间内亮着的灯的个数,我们可以把区间修改的线段树改一下,原本的求和改成若有奇数次更改则取反(总长度-亮着的灯个数),而判断是否奇数次只要数组加一个delta的值,update的时候delta xor 1 就够了,代码如下. 1 type 2 tpoint=record 3 l,r,sum,delta,mid:longint; 4 end; 5 var n,m,s,e,i,j,c,sum:longint; 6 tree:array[0..300000] of tpoi

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

递归不要加inline 会出现神奇的错误..... 1 #include <iostream> 2 #include <cstdio> 3 #define N 100010 4 using namespace std; 5 struct Tree 6 { 7 int size,rev,l,r; 8 }seg[N*4]; 9 int n,m; 10 inline int read() 11 { 12 char c; 13 int ans=0,f=1; 14 while (!isdig

bzoj1230:线段树+打标记

和白书讲的那道线段树区间修改的第二种类型很相似吧.写不算久: 1.在该区间更新说明必定牵涉这个区间,所以直接先pushdown: 2.往下传是对子区间的更新: 3.如果原来子节点没有标记,那么现在有了,如果原来子节点有标记,那么改了一边又把他改了回来所以没有标记了: ------------------------------------------------------------------------------ #include<cstdio>#include<cstring&

BZOJ 1230--lites 开关灯(线段树)

1230: [Usaco2008 Nov]lites 开关灯 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1682  Solved: 876[Submit][Status][Discuss] Description Farmer John尝试通过和奶牛们玩益智玩具来保持他的奶牛们思维敏捷. 其中一个大型玩具是牛栏中的灯. N (2 <= N <= 100,000) 头奶牛中的每一头被连续的编号为1..N, 站在一个彩色的灯下面.刚到傍晚的时候

【USACO 2008 Nov Gold】 3.Light Switching(lites 开关灯) 区间修改线段树

题意: n.m,n个灯,m次操作 两种操作 0: 这段区间全部状态取反,初始全部为0 1: 询问这段区间有几个灯是亮的. 裸线段树,弱爆了. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 101000 #define inf 0x3f3f3f3f using namespace std; struct Segment_Tree {