zoukankan      html  css  js  c++  java
  • mex(线段树+离散化)

    题目描述:

    给你一个无限长的数组,初始的时候都为0,有3种操作:

    操作1是把给定区间[l,r][l,r] 设为1,

    操作2是把给定区间[l,r][l,r] 设为0,

    操作3把给定区间[l,r][l,r] 0,1反转。

    一共n个操作,每次操作后要输出最小位置的0。

    题解:

    经过分析观察,可以发现,答案只有可能是1,l,r+1

    所以我们开一个数组记录1,以及所有的l,r,r+1,并离散化

    然后用线段树模拟操作即可

    这里有两种思路:

    一种是记录某一区间内0的最小位置和1的最小位置,反转时互换两个位置

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    const int maxn=3e5+5;
    int n,m;ll a[maxn];
    struct que{
        int op;ll l,r;
    }q[N];
    int s0[maxn<<2],s1[maxn<<2],lazy[maxn<<2],rev[maxn<<2];
    void pushup(int u){
        if(s0[u*2]) s0[u]=s0[u*2];
        else if(s0[u*2+1]) s0[u]=s0[u*2+1];
        else s0[u]=0;
        if(s1[u*2]) s1[u]=s1[u*2];
        else if(s1[u*2+1]) s1[u]=s1[u*2+1];
        else s1[u]=0;
    }
    void build(int u,int l,int r){
        rev[u]=0;lazy[u]=-1;
        if(l==r){
            s0[u]=l;s1[u]=0;
            return;
        }
        int mid=(l+r)/2;
        build(u*2,l,mid);
        build(u*2+1,mid+1,r);
        pushup(u);
    }
    void pushdown(int u,int l,int r){
        if(lazy[u]!=-1){
            lazy[u*2]=lazy[u];
            lazy[u*2+1]=lazy[u];
            rev[u*2]=rev[u*2+1]=0;
            int mid=(l+r)/2;
            if(lazy[u]==1){
                s0[u*2]=s0[u*2+1]=0;
                s1[u*2]=l,s1[u*2+1]=mid+1;
            } 
            else if(lazy[u]==0){
                s0[u*2]=l,s0[u*2+1]=mid+1;
                s1[u*2]=s1[u*2+1]=0;
            } 
            lazy[u]=-1;
        }
        if(rev[u]){
            if(lazy[u*2]!=-1) lazy[u*2]^=1;
            else rev[u*2]^=1;
            if(lazy[u*2+1]!=-1) lazy[u*2+1]^=1;
            else rev[u*2+1]^=1;
            swap(s0[u*2],s1[u*2]);
            swap(s0[u*2+1],s1[u*2+1]);
            rev[u]=0;
        }
    }
    void update(int u,int l,int r,int a,int b,int k){
        if(a<=l&&b>=r){
            lazy[u]=k;
            rev[u]=0;
            if(k==1) s0[u]=0,s1[u]=l;
            else if(k==0) s0[u]=l,s1[u]=0;
            return;
        }
        pushdown(u,l,r);
        int mid=(l+r)/2;
        if(a<=mid) update(u*2,l,mid,a,b,k);
        if(b>mid) update(u*2+1,mid+1,r,a,b,k);
        pushup(u);
    }
    void revere(int u,int l,int r,int a,int b){
        if(a<=l&&b>=r){
            if(lazy[u]==-1) rev[u]^=1;
            else lazy[u]^=1;
            swap(s0[u],s1[u]);
            return;
        }
        pushdown(u,l,r);
        int mid=(l+r)/2;
        if(a<=mid) revere(u*2,l,mid,a,b);
        if(b>mid) revere(u*2+1,mid+1,r,a,b);
        pushup(u);
    }
    int main(){
        scanf("%d",&m);
        a[++n]=1;
        for(int i=1;i<=m;i++){
            scanf("%d%lld%lld",&q[i].op,&q[i].l,&q[i].r);
            a[++n]=q[i].l;a[++n]=q[i].r;a[++n]=q[i].r+1;
        }
        sort(a+1,a+n+1);
        n=unique(a+1,a+1+n)-a-1;
        build(1,1,n);
        for(int i=1;i<=m;i++){
            if(q[i].op==1){
                int x=lower_bound(a+1,a+1+n,q[i].l)-a;
                int y=lower_bound(a+1,a+1+n,q[i].r)-a;
                update(1,1,n,x,y,1);
            }
            else if(q[i].op==2){
                int x=lower_bound(a+1,a+1+n,q[i].l)-a;
                int y=lower_bound(a+1,a+1+n,q[i].r)-a;
                update(1,1,n,x,y,0);
            }
            else{
                int x=lower_bound(a+1,a+1+n,q[i].l)-a;
                int y=lower_bound(a+1,a+1+n,q[i].r)-a;
                revere(1,1,n,x,y);
            }
            if(!s0[1]) printf("%lld
    ",a[n]+1);
            else printf("%lld
    ",a[s0[1]]);
        }
        return 0;
    }

    另一种是记录某一区间内1的个数,查询时如果一个区间内1的个数小于这个区间的总个数,则说明这个区间内有0,递归下去

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    const int maxn=3e5+5;
    int n,m;ll a[maxn];
    struct que{
        int op;ll l,r;
    }q[N];
    int sum[maxn<<2],lazy[maxn<<2],rev[maxn<<2];
    void build(int u,int l,int r){
        rev[u]=0;lazy[u]=-1;sum[u]=0;//错误1:一开始只在l==r时赋了初值 
        if(l==r) return;
        int mid=(l+r)/2;
        build(u*2,l,mid);
        build(u*2+1,mid+1,r);
        sum[u]=sum[u*2]+sum[u*2+1];
    }
    void pushdown(int u,int l,int r){
        int mid=(l+r)>>1;
        if(lazy[u]!=-1){
            lazy[u<<1]=lazy[u];
            lazy[u<<1|1]=lazy[u];
            rev[u<<1]=0;
            rev[u<<1|1]=0;
            if(lazy[u]==1){
                sum[u<<1]=mid-l+1;
                sum[u<<1|1]=r-mid;
            }
            else{
                sum[u<<1]=0;
                sum[u<<1|1]=0;
            }
            lazy[u]=-1;
        }
        if(rev[u]){
            if(lazy[u<<1]!=-1) lazy[u<<1]^=1;
            else rev[u<<1]^=1;
            if(lazy[u<<1|1]!=-1) lazy[u<<1|1]^=1;
            else rev[u<<1|1]^=1;
            sum[u<<1]=mid-l+1-sum[u<<1];
            sum[u<<1|1]=r-mid-sum[u<<1|1];
            rev[u]=0;
        }
        //还是错误2 
    }
    void update(int u,int l,int r,int a,int b,int p){
        if(a<=l&&b>=r){
            if(l==r){
                if(p==1) sum[u]=1;
                else if(p==2) sum[u]=0;
                else sum[u]^=1;
            }
            else{
                if(p==1){
                    lazy[u]=1;
                    rev[u]=0;
                    sum[u]=r-l+1;
                }
                else if(p==2){
                    lazy[u]=0;
                    rev[u]=0;
                    sum[u]=0;
                }
                else{
                    if(lazy[u]==-1) rev[u]^=1;
                    else lazy[u]^=1;
                    sum[u]=r-l+1-sum[u];
                }
                //错误2:lazy,rev是会相互影响的 
            }
            return;
        }
        pushdown(u,l,r);
        int mid=(l+r)/2;
        if(a<=mid) update(u*2,l,mid,a,b,p);
        if(b>mid) update(u*2+1,mid+1,r,a,b,p);
        sum[u]=sum[u*2]+sum[u*2+1];
    }
    ll query(int u,int l,int r){
        if(l==r) return a[l];
        pushdown(u,l,r);
        int mid=(l+r)>>1;
        if(sum[u<<1]<mid-l+1) return query(u<<1,l,mid);
        else return query(u<<1|1,mid+1,r);
    }
    int main(){
        scanf("%d",&m);
        a[++n]=1;
        for(int i=1;i<=m;i++){
            scanf("%d%lld%lld",&q[i].op,&q[i].l,&q[i].r);
            a[++n]=q[i].l;a[++n]=q[i].r;a[++n]=q[i].r+1;
        }
        sort(a+1,a+n+1);
        n=unique(a+1,a+1+n)-a-1;
        build(1,1,n);
        for(int i=1;i<=m;i++){
            int x=lower_bound(a+1,a+1+n,q[i].l)-a;
            int y=lower_bound(a+1,a+1+n,q[i].r)-a;
            update(1,1,n,x,y,q[i].op);
            printf("%lld
    ",query(1,1,n));
        }
        return 0;
    }
  • 相关阅读:
    minimum-path-sum
    pascals-triangle
    Java -- 二分查找
    redis缓存雪崩,击穿,穿透(copy)
    使用redis限制提交次数
    数据库的悲观锁和乐观锁
    mysql常用命令
    php压缩Zip文件和文件打包下载
    php去除数据库的数据空格
    php获取本年、本月、本周时间戳和日期格式的实例代码(分析)
  • 原文地址:https://www.cnblogs.com/HarryPotter-fan/p/11378779.html
Copyright © 2011-2022 走看看