题目连接: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 ",query(1,1,n,x,y)); 74 } 75 } 76 return 0; 77 }