zoukankan      html  css  js  c++  java
  • 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
    ",lef);
        return 0;
    }
  • 相关阅读:
    Linux命令之cat
    Linux命令之diff
    Linux查看内核信息或系统信息
    Linux命令之touch
    linux脚本:shell, 判断输入参数的个数(命令行)
    c++中try catch的用法
    linux命令:ftp
    linux shell种类
    linux shell脚本:在脚本中实现读取键盘输入,根据输入判断下一步的分支
    c语言,gdb
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12237072.html
Copyright © 2011-2022 走看看