dtoi4538 「TJOI / HEOI2016」排序

题意:

     给一个1-n的全排列,q次操作,每次操作排序一段区间(升序或降序都有可能),最后问第k个位置是多少。

     n<=100000,q<=100000。

题解:

     显然,此题直接模拟效率为O(nqlogn),过不去。

     我们无法做到快速的排序一段数值在[1,n]范围内的区间,但是我们可以用logn的时间做到排序一段数值在[0,1]的区间。

     方法很简单,只需要用线段树求出该区间有多少个0和1,然后前一部分赋值为0(或1),后一部分赋值为1(或0)即可。

     由于这题只需要求出某一个位置的值,所以不需要确切的知道每一个位置的值。

     考虑二分一个答案,判断这个位置的值是否大于它。判断方法就是把大于mid的值设为1,小于等于mid的设为0,然后直接模拟排序即可。

     感觉还是二分不那么容易想到。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,m,a[100002],qq,mid;
typedef struct{
    bool u;
    int l,r;
}P;
typedef struct{
    int sum0,f;
}PP;
P q[100002];
PP p[400002];
void build(int root,int begin,int end){
    p[root].f=-1;
    if (begin==end)
    {
        p[root].sum0=(a[begin]<=mid);return;
    }
    int mid=(begin+end)/2;
    build(root*2,begin,mid);build(root*2+1,mid+1,end);
    p[root].sum0=p[root*2].sum0+p[root*2+1].sum0;
}
void pushdown(int root,int begin,int mid,int end){
    if (p[root].f==0)
    {
        p[root*2].sum0=mid-begin+1;p[root*2+1].sum0=end-mid;
        p[root*2].f=p[root*2+1].f=0;
        p[root].f=-1;
    }
    if (p[root].f==1)
    {
        p[root*2].sum0=p[root*2+1].sum0=0;
        p[root*2].f=p[root*2+1].f=1;
        p[root].f=-1;
    }
}
void gx0(int root,int begin,int end,int begin2,int end2){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        p[root].sum0=end-begin+1;p[root].f=0;
        return;
    }
    int mid=(begin+end)/2;pushdown(root,begin,mid,end);
    gx0(root*2,begin,mid,begin2,end2);gx0(root*2+1,mid+1,end,begin2,end2);
    p[root].sum0=p[root*2].sum0+p[root*2+1].sum0;
}
void gx1(int root,int begin,int end,int begin2,int end2){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        p[root].sum0=0;p[root].f=1;
        return;
    }
    int mid=(begin+end)/2;pushdown(root,begin,mid,end);
    gx1(root*2,begin,mid,begin2,end2);gx1(root*2+1,mid+1,end,begin2,end2);
    p[root].sum0=p[root*2].sum0+p[root*2+1].sum0;
}
int cx(int root,int begin,int end,int begin2,int end2){
    if (begin>end2 || end<begin2)return 0;
    if (begin>=begin2 && end<=end2)return p[root].sum0;
    int mid=(begin+end)/2;pushdown(root,begin,mid,end);
    return cx(root*2,begin,mid,begin2,end2)+cx(root*2+1,mid+1,end,begin2,end2); 
}
bool chaxun(int root,int begin,int end,int wz){
    if (begin==end)return !(p[root].sum0==1);
    int mid=(begin+end)/2;pushdown(root,begin,mid,end);
    if (wz<=mid)return chaxun(root*2,begin,mid,wz);
    else return chaxun(root*2+1,mid+1,end,wz);
}
bool pd(){
    build(1,1,n);
    for (int i=1;i<=m;i++)
    if (!q[i].u)
    {
        int l=q[i].r-q[i].l+1,d0=cx(1,1,n,q[i].l,q[i].r);int d1=l-d0;
        gx0(1,1,n,q[i].l,q[i].l+d0-1);gx1(1,1,n,q[i].l+d0,q[i].r);
    }
    else
    {
        int l=q[i].r-q[i].l+1,d0=cx(1,1,n,q[i].l,q[i].r);int d1=l-d0;
        gx1(1,1,n,q[i].l,q[i].l+d1-1);gx0(1,1,n,q[i].l+d1,q[i].r);
    }
    return chaxun(1,1,n,qq);
}
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].u,&q[i].l,&q[i].r);
    scanf("%d",&qq);
    int lef=1,righ=n;
    while(lef<righ)
    {
        mid=(lef+righ)/2;
        if (pd()==0)righ=mid;else lef=mid+1;
    }
    printf("%d\n",lef);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/1124828077ccj/p/12237072.html
今日推荐