zoukankan      html  css  js  c++  java
  • LuoguP2846[USACO08NOV]光开关Light Switching【线段树维护区间异或】By cellur925

    题目传送门

    题目大意,给你一串灯,按一下开关可以将灯的状态取反(开变成关,关变成开)。维护这个序列的两种操作:询问区间内有多少灯是开着的,区间按灯。


    开始想的是分别维护区间内0的数量,1的数量,两个懒标记。后来真正写到维护懒标记的时候却感觉不太可行,因为你并不精确的知道区间内哪里是开着,哪里是关着的。


    其实我们本质上就是在维护整个异或序列。因为把每个位置取反,实际上就是在进行异或运算。(0->1,1->0)。这样我们在区间修改的时候,只需要维护区间内1的个数,把它用区间长度减去原来的值便得到新值。而懒标记的维护,直接进行异或运算即可。因为懒标记实际上就是在告诉儿子节点怎么做,传递简单的修改无法维护的信息。所以直接异或即可。

    这个问题还有一个加加加加加加强版,bzoj1858,有时间干掉他。

    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define maxn 100090 
     4 
     5 using namespace std;
     6 
     7 int n,m;
     8 struct SegmentTree{
     9     int l,r,len;
    10     int val,lazy;
    11 }t[maxn*4];
    12 
    13 void build(int p,int l,int r)
    14 {
    15     t[p].l=l,t[p].r=r,t[p].len=r-l+1;
    16     if(l==r)
    17         return ;
    18     int mid=(l+r)>>1;
    19     build(p*2,l,mid);
    20     build(p*2+1,mid+1,r);
    21 }
    22 
    23 void update(int p)
    24 {
    25     if(t[p].l==t[p].r) return ;
    26     if(!t[p].lazy) return ;
    27     t[p*2].val=t[p*2].len-t[p*2].val;
    28     t[p*2+1].val=t[p*2+1].len-t[p*2+1].val;
    29     t[p*2].lazy^=1;
    30     t[p*2+1].lazy^=1;
    31     t[p].lazy=0;
    32 }
    33 
    34 void change(int p,int l,int r)
    35 {
    36     update(p);
    37     if(t[p].l==l&&t[p].r==r)
    38     {
    39         t[p].lazy^=1;
    40         t[p].val=t[p].len-t[p].val;
    41         return ;
    42     }
    43     int mid=(t[p].l+t[p].r)>>1;
    44     if(l>mid) change(p*2+1,l,r);
    45     else if(r<=mid) change(p*2,l,r);
    46     else change(p*2,l,mid),change(p*2+1,mid+1,r);
    47     t[p].val=t[p*2].val+t[p*2+1].val;
    48 }
    49 
    50 int ask(int p,int l,int r)
    51 {
    52     update(p);
    53     if(t[p].l==l&&t[p].r==r) return t[p].val;
    54     int mid=(t[p].l+t[p].r)>>1;
    55     if(l>mid) return ask(p*2+1,l,r);
    56     else if(r<=mid) return ask(p*2,l,r);
    57     else return ask(p*2,l,mid)+ask(p*2+1,mid+1,r);
    58 }
    59 
    60 int main()
    61 {
    62     scanf("%d%d",&n,&m);
    63     build(1,1,n);
    64     for(int i=1;i<=m;i++)
    65     {
    66         int opt=0,l=0,r=0;
    67         scanf("%d%d%d",&opt,&l,&r);
    68         if(opt==0)
    69             change(1,l,r);
    70         else if(opt==1)
    71             printf("%d
    ",ask(1,l,r));
    72     }
    73     return 0;
    74 }
    View Code
  • 相关阅读:
    bzoj 4566: [Haoi2016]找相同字符
    杜教筛模板
    bzoj 3772 :精神污染 线段树+打标记 or 主席树
    bzoj 3779: 重组病毒
    bzoj 3357: [Usaco2004]等差数列
    bzoj 3551: [ONTAK2010]Peaks加强版
    bzoj 4358: permu 莫队
    线段树分裂合并
    bzoj 3065 带插入区间k小值
    子串 [NOIP2015]
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9752356.html
Copyright © 2011-2022 走看看