zoukankan      html  css  js  c++  java
  • 线段树维护区间01

    G. 小 W 开关灯 Problem 4467  ] Discussion ]


    Description

    晚上到家小 W 通过开关灯来保持自己神经的兴奋以便清醒地理笔记。N(2N100,000)盏灯被连续的编号为 1N。刚回到家的时候,所有的灯都是关闭的。 
    小W 通过 N个按钮来控制灯的开关, 按第 i 个按钮可以改变第 i 盏灯的状态。 
    小W 发出 M (1M100,000)条指令,每个指令都是两个整数中的一个(0 或 1)。 
    第1 种指令(用 0 表示)包含两个数字 SiSi 和 Ei(1SiEiN),它们表示起始开关和终止开关。小 W 需要把从 Si 到 Ei之间的按钮都按一次,就可以完成这个指令。 
    第2 种指令(用 1 表示)同样包含两个数字 Si 和 Ei(1SiEiN),不过这种指令是询问从 Si 到 Ei 之间的灯有多少是亮着的。 

    请你帮助小 W 得到正确的答案。 

    Input

    第1 行: 用空格隔开的两个整数 N 和 M。 
    第2..M+1 行: 每行表示一个操作, 有三个用空格分开的整数: 指令号, Si 和 Ei。 

    Output

    对于每一次询问, 输出一行表示询问的结果。

    Samples

    Input Copy
    4 5
    0 1 2
    0 2 4
    1 2 3
    0 2 4
    1 1 4
    Output
    1
    2

    Hint

    【样例解释】
    一共有 4 盏灯, 5 个指令。 下面是执行的情况:
    1 2 3 4
     

    Init: O O O O O = 关 * = 开
    0 1 2 -> * * O O 改变灯 1 和 2 的状态
    0 2 4 -> * O * *

    1 2 3 -> 1 输出在 2..3 的范围内有多少灯是亮的
    0 2 4 -> * * O O 改变灯 2 ,3 和 4 的状态
    1 1 4 -> 2 输出在 1..4 的范围内有多少灯是亮的

    【数据规模】

    • 对于 20% 的数据: 1N,M100
    • 对于 40% 的数据: 1N,M10000
    • 对于另外 30% 的数据: 只有最后一组是 1 指令,前 M-1 组为 0 指令。
    • 对于 100% 的数据: 1N,M100000

    Source

    石光中学 2018泉州集训提高组day4
    这个题一看就是要用线段树做
    主要是要知道一个知识 t[p].s=t[p].r-t[p].l+1-t[p].s;(就是区间长度为5,有两个2,t[p].s=2,如果反转的话,t[p].s=5-2=3)
    这个就是区间变化之后怎么区间和
    然后在弄一个区间懒惰标记判断要不要下传标记,就是区间是不是要变换
    #pragma GCC optimize(1)
    #pragma GCC optimize(2)
    #pragma GCC optimize(3,"Ofast","inline")
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    template <typename Tp>
    void read(Tp &x){
        x=0;char ch=1;int fh;
        while(ch!='-'&&(ch>'9'||ch<'0')){
            ch=getchar();
        }
        if(ch=='-'){
            fh=-1;ch=getchar();
        }else fh=1;
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
        }
        x*=fh;
    }
    inline char read1()
    {
        register char ch=getchar();
        while(ch<'A'||ch>'M')ch=getchar();
        return ch;
    }
    const int maxn=5e6+100; 
    struct node{
        int l,r;
        int s;
        int lazy;
    }t[maxn];
    void build(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        if(l==r){
            return ;
        }
        int mid=(l+r)/2;
        build(2*p,l,mid);
        build(2*p+1,mid+1,r);
    } 
    void push(int p){
        if(t[p].lazy){
            t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s;
            t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s;
            t[2*p].lazy^=1;
            t[2*p+1].lazy^=1;
            t[p].lazy=0;
        } 
    }
    void update(int p,int l,int r){ 
        if(t[p].l>=l&&t[p].r<=r){ 
            t[p].s=t[p].r-t[p].l+1-t[p].s;
            t[p].lazy^=1;
            return ;
        } 
        if(t[p].lazy) push(p);
        int mid=(t[p].l+t[p].r)/2; 
        if(l<=mid){
            update(2*p,l,r); 
        }
        if(r>mid){
            update(2*p+1,l,r);
        }
        t[p].s=t[2*p].s+t[2*p+1].s; 
    } 
    int query(int p,int l,int r){
        if(t[p].l>=l&&t[p].r<=r){
            return t[p].s;
        }
        int ans=0;
        if(t[p].lazy) push(p);
        int mid=(t[p].l+t[p].r)/2; 
        if(l<=mid){
            ans+=query(2*p,l,r);
        }
        if(r>mid){
            ans+=query(2*p+1,l,r);
        }
        return ans;
    }
    int n,m;
    int main(){
        cin>>n>>m;
        int op,x,y;
        build(1,1,n); 
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&op,&x,&y);
            if(op==0){
                update(1,x,y);
            }
            else if(op==1){
                printf("%d
    ",query(1,x,y));
            }
        }
        
    }
     一开始wa了好几遍是这样写的,就是没有异或1,而是变化一次就把他变成一
    void push(int p){
        if(t[p].lazy){
            t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s;
            t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s;
            t[2*p].lazy=1;
            t[2*p+1].lazy=1;
            t[p].lazy=0;
        } 
    }
    void update(int p,int l,int r){ 
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){ 
            t[p].s=(R-L+1)-t[p].s;
            t[p].lazy=1;
            return ;
        } 

    这样有一个问题,就是

     就是1-2区间变化两次,而这个区间是一整个节点没有在update中下传标记,在询问中下传标记时下传了一次,

    本来该没有变化的,就是如果用异或的话询问两次的话,就变成0了,就不会出现上面的情况了

    #pragma GCC optimize(1)
    #pragma GCC optimize(2)
    #pragma GCC optimize(3,"Ofast","inline")
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    template <typename Tp>
    void read(Tp &x){
        x=0;char ch=1;int fh;
        while(ch!='-'&&(ch>'9'||ch<'0')){
            ch=getchar();
        }
        if(ch=='-'){
            fh=-1;ch=getchar();
        }else fh=1;
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
        }
        x*=fh;
    }
    inline char read1()
    {
        register char ch=getchar();
        while(ch<'A'||ch>'M')ch=getchar();
        return ch;
    }
    const int maxn=5e6+100; 
    struct node{
        int l,r;
        int s;
        int lazy;
    }t[maxn];
    void build(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        if(l==r){
            return ;
        }
        int mid=(l+r)/2;
        build(2*p,l,mid);
        build(2*p+1,mid+1,r);
    } 
    void push(int p){
        if(t[p].lazy){
            t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s;
            t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s;
            t[2*p].lazy^=1;
            t[2*p+1].lazy^=1;
            t[p].lazy=0;
        } 
    }
    void update(int p,int l,int r){ 
        if(t[p].l>=l&&t[p].r<=r){ 
            t[p].s=t[p].r-t[p].l+1-t[p].s;
            t[p].lazy^=1;
            return ;
        } 
        if(t[p].lazy) push(p);
        int mid=(t[p].l+t[p].r)/2; 
        if(l<=mid){
            update(2*p,l,r); 
        }
        if(r>mid){
            update(2*p+1,l,r);
        }
        t[p].s=t[2*p].s+t[2*p+1].s; 
    } 
    int query(int p,int l,int r){
        if(t[p].l>=l&&t[p].r<=r){
            return t[p].s;
        }
        int ans=0;
        if(t[p].lazy) push(p);
        int mid=(t[p].l+t[p].r)/2; 
        if(l<=mid){
            ans+=query(2*p,l,r);
        }
        if(r>mid){
            ans+=query(2*p+1,l,r);
        }
        return ans;
    }
    int n,m;
    int main(){
        cin>>n>>m;
        int op,x,y;
        build(1,1,n); 
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&op,&x,&y);
            if(op==0){
                update(1,x,y);
            }
            else if(op==1){
                printf("%d
    ",query(1,x,y));
            }
        }
        
    }
     
  • 相关阅读:
    人脸识别常用的性能评价指标
    【计算机视觉】seetaFace
    【error】'isnan' was not declared in this scope
    【opencv基础】图像的几何变换
    [c++]base64编解码 and image
    【leetcode】232-Implement Queue using Stacks
    【leetcode】231-power-of-two
    C++中vector容器的常用操作方法实例总结
    【leetcode】226-invert-binary-tree
    第3章 文件I/O(2)_文件I/O系统调用及文件描述符
  • 原文地址:https://www.cnblogs.com/lipu123/p/14305772.html
Copyright © 2011-2022 走看看