• 【线段树】Bzoj1230 [Usaco2008 Nov]lites 开关灯


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

    Solution

    记录两个量tag和sum,用lazy维护。

    刷水+复习线段树。

    Code

    lazy处理祖先对后代的方法有两种,递归时记录或每次都pushdown,前者常数小但后者更无脑不容易错。

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=4e5+5;
     5 
     6 int tag[maxn],sum[maxn];
     7 int n,m;
     8 int x,p,q,ret;
     9 
    10 int pushup(int o){
    11     sum[o]=sum[o*2]+sum[o*2+1];
    12 }
    13 
    14 int pushdown(int o,int l,int r){
    15     int mid=(l+r)>>1;
    16     tag[o]=0;
    17     tag[o*2]^=1,tag[o*2+1]^=1;
    18     sum[o*2]=(mid-l+1-sum[o*2]);
    19     sum[o*2+1]=(r-mid-sum[o*2+1]);
    20 }
    21 
    22 void add(int o,int l,int r){
    23     if(p<=l&&r<=q){
    24         tag[o]^=1;
    25         sum[o]=(r-l+1-sum[o]);
    26         return;
    27     }
    28     if(tag[o]) pushdown(o,l,r);
    29     int mid=(l+r)>>1;
    30     if(p<=mid) add(o*2,l,mid);
    31     if(q>mid) add(o*2+1,mid+1,r);
    32     pushup(o);
    33 }
    34 
    35 void ask(int o,int l,int r,int k){
    36     if(p<=l&&r<=q){
    37         if(!k) ret+=sum[o];
    38         else ret+=(r-l+1-sum[o]);
    39         return;
    40     }
    41     int mid=(l+r)>>1;
    42     if(p<=mid) ask(o*2,l,mid,k^tag[o]);
    43     if(q>mid) ask(o*2+1,mid+1,r,k^tag[o]);
    44 }
    45 
    46 int main(){
    47     scanf("%d%d",&n,&m);
    48     for(int i=1;i<=m;i++){
    49         scanf("%d%d%d",&x,&p,&q);
    50         if(x==0) add(1,1,n);
    51         else{
    52             ret=0;
    53             ask(1,1,n,0);
    54             printf("%d
    ",ret);
    55         }
    56     }
    57     return 0;
    58 }

    每次都pushdown代码

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=4e5+5;
     5 
     6 int tag[maxn],sum[maxn];
     7 int n,m;
     8 int x,p,q,ret;
     9 
    10 int pushup(int o){
    11     sum[o]=sum[o*2]+sum[o*2+1];
    12 }
    13 
    14 int pushdown(int o,int l,int r){
    15     int mid=(l+r)>>1;
    16     tag[o]=0;
    17     tag[o*2]^=1,tag[o*2+1]^=1;
    18     sum[o*2]=(mid-l+1-sum[o*2]);
    19     sum[o*2+1]=(r-mid-sum[o*2+1]);
    20 }
    21 
    22 void add(int o,int l,int r){
    23     if(p<=l&&r<=q){
    24         tag[o]^=1;
    25         sum[o]=(r-l+1-sum[o]);
    26         return;
    27     }
    28     if(tag[o]) pushdown(o,l,r);
    29     int mid=(l+r)>>1;
    30     if(p<=mid) add(o*2,l,mid);
    31     if(q>mid) add(o*2+1,mid+1,r);
    32     pushup(o);
    33 }
    34 
    35 void ask(int o,int l,int r){
    36     if(p<=l&&r<=q){
    37         ret+=sum[o];
    38         return;
    39     }
    40     if(tag[o]) pushdown(o,l,r);
    41     int mid=(l+r)>>1;
    42     if(p<=mid) ask(o*2,l,mid);
    43     if(q>mid) ask(o*2+1,mid+1,r);
    44     pushup(o);
    45 }
    46 
    47 int main(){
    48     scanf("%d%d",&n,&m);
    49     for(int i=1;i<=m;i++){
    50         scanf("%d%d%d",&x,&p,&q);
    51         if(x==0) add(1,1,n);
    52         else{
    53             ret=0;
    54             ask(1,1,n);
    55             printf("%d
    ",ret);
    56         }
    57     }
    58     return 0;
    59 }
    View Code
  • 相关阅读:
    《C++反汇编与逆向分析技术揭秘》--构造函数 读书笔记
    《C++反汇编与逆向分析技术揭秘》--虚函数 读书笔记
    VPP-main() 源码学习
    【转】几种TCP连接中出现RST的情况
    动态追踪学习
    RCU学习总结
    内核栈回溯原理学习应用
    《C++反汇编与逆向分析技术揭秘》--单类继承 读书笔记
    C# 防火墙操作之创建规则
    C# 防火墙操作之特定程序
  • 原文地址:https://www.cnblogs.com/xkui/p/4558836.html
Copyright © 2020-2023  润新知