zoukankan      html  css  js  c++  java
  • 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);
    }
  • 相关阅读:
    内存泄漏 Memory Leaks 内存优化 MD
    Handler Thread 内部类引起内存泄露分析
    为什么不取消注册BroadcastReceiver会导致内存泄漏
    WebChromeClient 简介 API 案例
    WebViewClient 简介 API 案例
    java.net.URI 简介 文档 API
    android.net.Uri 简介 API
    RV 多样式 MultiType 聊天界面 消息类型 MD
    JS函数声明与定义,作用域,函数声明与表达式的区别
    CSS中table tr:nth-child(even)改变tr背景颜色: IE7,8无效
  • 原文地址:https://www.cnblogs.com/birchtree/p/9858037.html
Copyright © 2011-2022 走看看