bzoj1230 : [Usaco2008 Nov]lites 开关灯

1230: [Usaco2008 Nov]lites 开关灯

 

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 418  Solved: 221

[Submit][Status][Discuss]

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确保他的奶牛们可以得到正确的答案.

Input

 

* 第 1 行: 用空格隔开的两个整数N和M * 第 2..M+1 行: 每行表示一个操作, 有三个用空格分开的整数: 指令号, S_i 和 E_i

Output

 

第 1..询问的次数 行: 对于每一次询问, 输出询问的结果.

Sample Input

 

4 5

 

0 1 2

 

0 2 4

 

1 2 3

 

0 2 4

 

1 1 4

 

 

 

输入解释:

 

一共有4盏灯; 5个指令. 下面是执行的情况:

 

       灯

 

            1 2 3 4

 

  Init:     O O O O   O = 关  * = 开

 

  0 1 2 ->  * * O O  改变灯 1 和 2 的状态

 

  0 2 4 ->  * O * *

 

  1 2 3 ->  1        输出在2..3的范围内有多少灯是亮的

 

  0 2 4 ->  * * O O  改变灯 2 ,3 和 4 的状态

 

  1 1 4 ->  2        输出在1..4的范围内有多少灯是亮的

 

 

 

 

 

 

 

 

 

Sample Output

 

1

 

2

 

HINT

 

Source

 

Gold

 

 

_________________________________

 

只好想好状态表示,基础线段树。

 

_________________________________

  1 Program Stone;
  2 
  3 var n,m,lc,rc,ans:longint;
  4 
  5     a:array[1..1 shl 18]of longint;   //记录该区间有几盏灯是开的
  6 
  7     b:array[1..1 shl 18]of boolean;   //以为两次操作等效与不操作,所以b记录该区间是否有操作。
  8 
  9  
 10 
 11  procedure change(num,head,tail,k:longint);     //将子区间的开关灯反转。
 12 
 13   begin
 14 
 15    a[num*2]:=k-head+1-a[num*2];b[num*2]:=not(b[num*2]);
 16 
 17    a[num*2+1]:=tail-k-a[num*2+1];b[num*2+1]:=not(b[num*2+1]);
 18 
 19    b[num]:=false;           //修改标记。
 20 
 21   end;
 22 
 23  procedure update(head,tail,num:longint);   //修改
 24 
 25  var i,j,k:longint;
 26 
 27   begin
 28 
 29    if (lc<=head)and(tail<=rc) then begin
 30 
 31                                     a[num]:=tail-head+1-a[num];  //按一次开关,即将开的灯与关的等个数反转。
 32 
 33                                     b[num]:=not(b[num]);         //改变状态。
 34 
 35                                     exit;
 36 
 37                                    end;
 38 
 39    k:=(head+tail)div 2;
 40 
 41    if b[num] then change(num,head,tail,k);    //如果区间被操作了,那么修改子区间。
 42 
 43    if lc<=k then update(head,k,num*2);
 44 
 45    if rc>k  then update(k+1,tail,num*2+1);
 46 
 47    a[num]:=a[num*2]+a[num*2+1];
 48 
 49   end;
 50 
 51  
 52 
 53  procedure query(head,tail,num:longint);   //询问
 54 
 55  var i,j,k:longint;
 56 
 57   begin
 58 
 59    if (lc<=head)and(tail<=rc) then begin
 60 
 61                                     inc(ans,a[num]);   //加入答案
 62 
 63                                     exit;
 64 
 65                                    end;
 66 
 67    k:=(head+tail)div 2;
 68 
 69    if b[num] then change(num,head,tail,k);   //修改子区间
 70 
 71    if lc<=k then query(head,k,num*2);
 72 
 73    if rc>k  then query(k+1,tail,num*2+1);
 74 
 75   end;
 76 
 77  
 78 
 79  procedure init;
 80 
 81  var i,j,k,x,y,z:longint;
 82 
 83   begin
 84 
 85     fillchar(b,sizeof(b),false);
 86 
 87     readln(n,m);
 88 
 89     for i:=1 to m do
 90 
 91      begin
 92 
 93       readln(x,lc,rc);
 94 
 95       if x=0 then update(1,n,1)
 96 
 97              else begin
 98 
 99                    ans:=0;
100 
101                    query(1,n,1);
102 
103                    writeln(ans);
104 
105                   end;
106 
107      end;
108 
109   end;
110 
111 Begin
112 
113  assign(input,'input.in');reset(input);
114 
115  init;
116 
117  close(input);
118 
119 end.

 

posted on 2016-03-02 17:41  Yesphet  阅读(316)  评论(0编辑  收藏  举报