• BZOJ 4552(二分+线段树+思维)


    题面

    传送门

    分析

    此题是道好题!
    首先要跳出思维定势,不是去想如何用数据结构去直接维护排序过程,而是尝试二分a[p]的值
    设二分a[p]的值为x
    我们将大于x的数标记为1,小于等于x的数标记为0
    则整个序列只由01组成,记为b
    将一个区间升序排序,则相当于将1全部移到右边,0全部移到左边,降序排序反之
    例:
    a={1,6,5,2,4,3}.x=4
    标记后的序列b为{0,1,1,0,0,0}
    此时对[1,5]进行升序排序,a={1,2,4,5,6,3}
    标记后的序列b为{0,0,0,1,1,0}

    因此可以用线段树维护标记后的序列,直接区间求和得到1的个数,再区间更新即可
    如果排完序后b[p]=0,则说明a[p]<=x,继续减小x
    否则增大x

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    using namespace std;
    int n,m,qa;
    struct node {
        int l;
        int r;
        int v;
        int mark;
        int len() {
            return r-l+1;
        }
    } tree[maxn<<2];
    int a[maxn];
    struct sort_seg {
        int l;
        int r;
        int type;
    } q[maxn];
    void push_up(int pos) {
        tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
    }
    void build(int l,int r,int pos,int middle) {
        tree[pos].l=l;
        tree[pos].r=r;
        tree[pos].v=0;
        tree[pos].mark=-1;
        if(l==r) {
            tree[pos].v=(a[l]>middle);
            return;
        }
        int mid=(tree[pos].l+tree[pos].r)>>1;
        build(l,mid,pos<<1,middle);
        build(mid+1,r,pos<<1|1, middle);
        push_up(pos);
    }
    void push_down(int pos) {
        if(tree[pos].mark!=-1) {
            tree[pos<<1].mark=tree[pos].mark;
            tree[pos<<1|1].mark=tree[pos].mark;
            tree[pos<<1].v=tree[pos].mark*tree[pos<<1].len();
            tree[pos<<1|1].v=tree[pos].mark*tree[pos<<1|1].len();
            tree[pos].mark=-1;
        }
    }
    void update(int L,int R,int v,int pos) {
        if(R<tree[pos].l||L>tree[pos].r) return;
        if(L<=tree[pos].l&&R>=tree[pos].r) {
            tree[pos].v=v*tree[pos].len();
            tree[pos].mark=v;
            return;
        }
        push_down(pos);
        int mid=(tree[pos].l+tree[pos].r)>>1;
        if(L<=mid) update(L,R,v,pos<<1);
        if(R>mid) update(L,R,v,pos<<1|1);
        push_up(pos);
    }
    int query(int L,int R,int pos) {
        if(R<tree[pos].l||L>tree[pos].r) return 0;
        if(L<=tree[pos].l&&R>=tree[pos].r) {
            return tree[pos].v;
        }
        push_down(pos);
        int mid=(tree[pos].l+tree[pos].r)>>1;
        int ans=0;
        if(L<=mid) ans+=query(L,R,pos<<1);
        if(R>mid) ans+=query(L,R,pos<<1|1);
        return ans;
    }
    int check(int x) {
        build(1,n,1,x);
        for(int i=1; i<=m; i++) {
            int sum=query(q[i].l,q[i].r,1);
            if(q[i].type==0) {
                update(q[i].l,q[i].r-sum,0,1);
                update(q[i].r-sum+1,q[i].r,1,1);
            } else {
                update(q[i].l,q[i].l+sum-1,1,1);
                update(q[i].l+sum,q[i].r,0,1);
            }
        }
        if(query(qa,qa,1)==1) return 0;
        else return 1;
    }
    int main() {
        scanf("%d %d",&n,&m);
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[i]);
        }
        for(int i=1; i<=m; i++) {
            scanf("%d %d %d",&q[i].type,&q[i].l,&q[i].r);
        }
        int l=1,r=n;
        int ans=n+1;
        scanf("%d",&qa);
        while(l<=r) {
            int mid=(l+r)>>1;
            if(check(mid)) {
                ans=min(ans,mid);
                r=mid-1;
            } else {
                l=mid+1;
            }
        }
        printf("%d
    ",ans);
    }
  • 相关阅读:
    dN/dS与分子进化常用软件
    samtools和bcftools使用说明
    变异检测VarScan软件使用说明
    线程可以共享进程里的哪些资源
    函数调用与系统调用的区别
    海量数据统计出现次数
    海量数据查找问题
    建立高并发模型需要考虑的点
    言简意赅的TIME_WAIT
    常用的TCP选项
  • 原文地址:https://www.cnblogs.com/birchtree/p/9858037.html
Copyright © 2020-2023  润新知