题目连接:。
题意:有若干个灯泡,每次对一段操作,这一段原先是亮的,就关了;原先是关着的,就打开。询问某一段的打开的灯泡的个数。
分析:很显然的成段更新,但是一开始想着用某段是不是相同的来维护,敲了很长时间都没有实现。后来经过大力学长知道,对有懒惰标记的节点的亮着的灯泡的和这么更新即可:c[o]=r-l+1-c[o]; 简直奥义!
另外,从这题可以看出,我对于成段更新的懒惰标记理解不够深刻。应该理解如下:对某点进行pushdown操作时,这点的sum值不更新,更新子节点的sum和add值即可。
具体见代码:
1 #include2 #include 3 #include 4 #include 5 #include 6 #define t_mid (l+r>>1) 7 #define ls (o<<1) 8 #define rs (o<<1 | 1) 9 #define lson ls,l,t_mid10 #define rson rs,t_mid+1,r11 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 }