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.