题目连接:http://www.spoj.com/problems/LITE/en/

  题意:有若干个灯泡,每次对一段操作,这一段原先是亮的,就关了;原先是关着的,就打开。询问某一段的打开的灯泡的个数。

  分析:很显然的成段更新,但是一开始想着用某段是不是相同的来维护,敲了很长时间都没有实现。后来经过大力学长知道,对有懒惰标记的节点的亮着的灯泡的和这么更新即可:c[o]=r-l+1-c[o]; 简直奥义!

  另外,从这题可以看出,我对于成段更新的懒惰标记理解不够深刻。应该理解如下:对某点进行pushdown操作时,这点的sum值不更新,更新子节点的sum和add值即可

  具体见代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <set>
 5 #include <iostream>
 6 #define t_mid (l+r>>1)
 7 #define ls (o<<1)
 8 #define rs (o<<1 | 1)
 9 #define lson ls,l,t_mid
10 #define rson rs,t_mid+1,r
11 using namespace std;
12 const int N = 100000 + 5;
13 
14 int n,m,c[N<<2];
15 bool add[N<<2];
16 void build(int o,int l,int r)
17 {
18     c[o]=0,add[o]=0;
19     if(l==r) return;
20     build(lson);
21     build(rson);
22 }
23 void pushdown(int o,int len)
24 {
25     if(add[o])
26     {
27         c[ls]=(len-(len>>1))-c[ls];
28         c[rs]=(len>>1)-c[rs];
29         add[ls]^=1;
30         add[rs]^=1;
31         add[o]=0;
32     }
33 }
34 void pushup(int o)
35 {
36     c[o] = c[ls] + c[rs];
37 }
38 void update(int o,int l,int r,int ql,int qr)
39 {
40     if(ql<=l && qr>=r)
41     {
42         add[o]^=1;
43         c[o] = r-l+1-c[o];
44         return;
45     }
46     pushdown(o,r-l+1);
47     if(ql<=t_mid) update(lson,ql,qr);
48     if(qr>t_mid) update(rson,ql,qr);
49 
50     pushup(o);
51 }
52 int query(int o,int l,int r,int ql,int qr)
53 {
54     if(ql<=l && qr>=r) return c[o];
55     pushdown(o,r-l+1);
56     int res = 0;
57     if(ql<=t_mid) res += query(lson,ql,qr);
58     if(qr>t_mid) res += query(rson,ql,qr);
59     return res;
60 }
61 
62 int main()
63 {
64     while(scanf("%d%d",&n,&m)==2)
65     {
66         build(1,1,n);
67 
68         while(m--)
69         {
70             int op,x,y;
71             scanf("%d%d%d",&op,&x,&y);
72             if(!op) update(1,1,n,x,y);
73             else printf("%d\n",query(1,1,n,x,y));
74         }
75     }
76     return 0;
77 }