• 洛谷 P2824 [HEOI2016/TJOI2016]排序 解题报告


    P2824 [HEOI2016/TJOI2016]排序

    题意:

    有一个长度为(n)的1-n的排列(m)次操作
    ((0,l,r))表示序列从(l)(r)降序
    ((1,l,r))表示序列从(l)(r)升序
    问最终第(q)位的元素

    数据范围:

    (n,m<=1e5)


    二分答案神题。

    我们发现维护区间排序非常困难,然后最终只是若干修改一次询问。

    所以我们可以枚举第(q)位的是什么,然后把小于等于它的置0,大于它的置0。

    这样的话,我们就可以用支持区间查询和区间覆盖的线段树维护升降序了

    进一步的,我们发现第q位的数字满足单调性,于是二分答案

    复杂度:(O(nlog^2n))


    Code:

    #include <cstdio>
    #define ls id<<1
    #define rs id<<1|1
    const int N=30010;
    int dat[N<<2],lazy[N<<2],m,n,op[N],opr[N],opl[N],a[N],q;
    void build(int id,int l,int r,int M)
    {
        lazy[id]=-1;
        if(l==r)
        {
            dat[id]=(M<a[l]);
            return;
        }
        int mid=l+r>>1;
        build(ls,l,mid,M);
        build(rs,mid+1,r,M);
        dat[id]=dat[ls]+dat[rs];
    }
    void push_down(int id,int L,int R)
    {
        if(lazy[id]==-1) return;
        if(L!=R)
        {
            int mid=L+R>>1;
            dat[ls]=(mid+1-L)*lazy[id];
            dat[rs]=(R-mid)*lazy[id];
            lazy[ls]=lazy[rs]=lazy[id];
        }
        lazy[id]=-1;
    }
    void change(int id,int L,int R,int l,int r,int delta)
    {
        if(l>r) return;
        push_down(id,L,R);
        if(L==l&&R==r)
        {
            dat[id]=(r+1-l)*delta;
            lazy[id]=delta;
            return;
        }
        int mid=L+R>>1;
        if(r<=mid)
            change(ls,L,mid,l,r,delta);
        else if(l>mid)
            change(rs,mid+1,R,l,r,delta);
        else
            change(ls,L,mid,l,mid,delta),change(rs,mid+1,R,mid+1,r,delta);
        dat[id]=dat[ls]+dat[rs];
    }
    int query(int id,int L,int R,int l,int r)
    {
        push_down(id,L,R);
        if(L==l&&R==r)
            return dat[id];
        int mid=L+R>>1;
        if(r<=mid)
            return query(ls,L,mid,l,r);
        else if(l>mid)
            return query(rs,mid+1,R,l,r);
        else
            return query(ls,L,mid,l,mid)+query(rs,mid+1,R,mid+1,r);
    }
    bool check(int d)
    {
        build(1,1,n,d);
        for(int i=1;i<=m;i++)
        {
            int cn1=query(1,1,n,opl[i],opr[i]);
            int cn0=opr[i]+1-opl[i]-cn1;
            if(op[i]==0)
            {
                change(1,1,n,opl[i],opl[i]+cn0-1,0);
                change(1,1,n,opl[i]+cn0,opr[i],1);
            }
            else
            {
                change(1,1,n,opl[i],opl[i]+cn1-1,1);
                change(1,1,n,opl[i]+cn1,opr[i],0);
            }
        }
        return query(1,1,n,q,q);
    }
    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",op+i,opl+i,opr+i);
        scanf("%d",&q);
        int l=1,r=n;
        while(l<r)
        {
            int mid=l+r>>1;
            if(check(mid))
                l=mid+1;
            else
                r=mid;
        }
        printf("%d
    ",l);
        return 0;
    }
    

    2018.7.19

  • 相关阅读:
    函数计算入门-HelloWorld应用开发
    Linux指令入门-文本处理
    计算机网络概述
    管理Linux服务器用户和组
    jQuery事件对象和js对象创建(使用构造函数的方式)
    jQuery操作页面元素之css style操作
    jQuery操作页面元素之包装元素
    jQuery操作页面元素之元素插入
    jQuery操作页面元素之元素内容操作
    Qt中的信号和槽函数。
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9335388.html
Copyright © 2020-2023  润新知