[TJOI&HEOI2016]排序

来源:互联网 发布:js单例模式 命名空间 编辑:程序博客网 时间:2024/05/18 22:13

题目大意

有一个n的排列,进行m次操作,每次操作是将一个区间升序或降序排序。
请你输出m次操作后第p个位置的值。

数据范围

n,m≤100000

分析

直接排序肯定不好做。
但是如果考虑二分答案,那么问题就变成判断最后第p个位置的值是否小于等于一个数了。
所以对于当前二分的答案mid,把a[i]≤mid的都赋值为1,a[i]>mid的赋为0。以升序排序为例,求出区间有多少个1,假设共有cnt个,那么把这些1放在区间左边cnt个位置,右边的位置全部放0。这部分用线段树解决。

时间复杂度O(nlog2n)

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn=100005,maxt=262205;int n,m,a[maxn],q,l,r,mid,L[maxn],R[maxn],typ[maxn],t[maxt],mask[maxt];void insert(int l,int r,int a,int b,int v,int x){    if (l==a && r==b)    {        mask[x]=v;        t[x]=(r-l+1)*mask[x];        return;    }    int mid=(l+r)/2;    if (mask[x]>=0)    {        mask[x*2]=mask[x]; mask[x*2+1]=mask[x];        t[x*2]=mask[x]*(mid-l+1); t[x*2+1]=mask[x]*(r-mid);        mask[x]=-1;    }    if (b<=mid) insert(l,mid,a,b,v,x*2);    else if (a>mid) insert(mid+1,r,a,b,v,x*2+1);    else    {        insert(l,mid,a,mid,v,x*2); insert(mid+1,r,mid+1,b,v,x*2+1);    }    t[x]=t[x*2]+t[x*2+1];}int getsum(int l,int r,int a,int b,int x){    if (l==a && r==b) return t[x];    int mid=(l+r)/2;    if (mask[x]>=0)    {        mask[x*2]=mask[x]; mask[x*2+1]=mask[x];        t[x*2]=mask[x]*(mid-l+1); t[x*2+1]=mask[x]*(r-mid);        mask[x]=-1;    }    if (b<=mid) return getsum(l,mid,a,b,x*2);    if (a>mid) return getsum(mid+1,r,a,b,x*2+1);    return getsum(l,mid,a,mid,x*2)+getsum(mid+1,r,mid+1,b,x*2+1);}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    for (int i=0;i<m;i++) scanf("%d%d%d",&typ[i],&L[i],&R[i]);    scanf("%d",&q);    for (l=1,r=n,mid=(l+r)/2;l<r;mid=(l+r)/2)    {        memset(t,0,sizeof(t));        memset(mask,255,sizeof(mask));        for (int i=1;i<=n;i++) insert(1,n,i,i,(a[i]<=mid),1);        for (int i=0;i<m;i++)        {            int cnt=getsum(1,n,L[i],R[i],1);            if (!typ[i])            {                if (cnt) insert(1,n,L[i],L[i]+cnt-1,1,1);                if (cnt<R[i]-L[i]+1) insert(1,n,L[i]+cnt,R[i],0,1);            }else            {                if (cnt) insert(1,n,R[i]-cnt+1,R[i],1,1);                if (cnt<R[i]-L[i]+1) insert(1,n,L[i],R[i]-cnt,0,1);            }        }        if (getsum(1,n,q,q,1)) r=mid;else l=mid+1;    }    printf("%d\n",l);    return 0;}
0 0
原创粉丝点击