洛谷 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\n",l);
    return 0;
}

2018.7.19

posted @ 2018-07-19 13:55  露迭月  阅读(122)  评论(0编辑  收藏  举报