zoukankan      html  css  js  c++  java
  • 【luogu P2824排序】题解

    【HEOI2016/TJOI】排序

    题目描述

    在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字。

    输入格式

    输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。第二行为n个整数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置

    输出格式

    输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

    输入输出样例

    输入 #1
    6 3
    1 6 2 5 3 4
    0 1 4
    1 3 6
    0 2 4
    3
    输出 #1
    5

    说明/提示

    河北省选2016第一天第二题。

    对于30%的数据,n,mleq 1000n,m1000

    对于100%的数据,n,mleq 10^5n,m105且始终1leq qleq n1qn

    题意简单明了,但题目给了我一个很棒的思路。

    先想想暴力该怎么打。

    排序?我们看到了n的取值范围只有1e5,这显然给桶排带来了无限生机。记录下区间的min和max,这题可以暴力出80分的好成绩。

    虽然80分对我来说已经够了, 但是100分总是那么诱人。

    我们观察题目中给出的一些特殊性质。

    1、 对于[1,n]中每个元素只出现一次。

    2、 查询只有1次。

    这两个性质足够我们打出正解了。

    首先答案一定在[1,n]中。能不能二分答案?

    我们把操作离线,对于每个mid进行check。

    如何check?首先,我们把原序列中大于等于mid的标为1,小于mid的记做0。

    这样我们一趟排序下来,如果pos(查询的位置)为1,这代表说,pos是大于等于mid的,答案一定在[mid,r]中。

    反之,答案一定在[l,mid-1]中。

    那么这样做好在哪里呢?

    对于普通排序,顶多做到O(n),然而对于0,1序列的排序,可以做到O(log n)。

    如何操作?

    可以使用强大的线段树。线段树的区间查询,区间修改,可以用于0,1序列的排序。

    当对一个区间进行排序时,首先query出这个区间里1的个数,也就是区间和,记做cnt。

    若是降序排列,则把区间[l,l+cnt-1]修改为1,[l+cnt,r]修改为0。

    若是升序排列,则把区间[r-cnt+1,r]修改为1,[l,r-cnt]修改为0。

    上面就是基于线段树对0,1串的排序。

    总体时间复杂度O(mlognlogn)

    线段树的功能十分强大,区间修改是线段树最重要的功能之一,好好学习和运用,会有很大的帮助。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ls (k<<1)
    #define rs (k<<1|1)
    using namespace std;
    const int N=1e5+10;
    int tree[N<<2],tag[N<<2],a[N],op[N][5];//原先因为tag忘开4倍空间只有80分,给自己长个记性。
    int n,m,pos;
    inline void read(int &x){
        x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    }
    inline void build(int k,int x,int y,int val){
        if(x==y){
            tree[k]=(a[x]>=val?1:0);
            return;
        }
        int mid=x+y>>1;
        build(ls,x,mid,val);
        build(rs,mid+1,y,val);
        tree[k]=tree[ls]+tree[rs];
    }
    inline void update(int k,int x,int y){
        int mid=x+y>>1;
        tree[ls]=tag[k]*(mid-x+1);
        tree[rs]=tag[k]*(y-mid);
        tag[ls]=tag[k];
        tag[rs]=tag[k];
        tag[k]=-1;
    }
    inline int query(int k,int x,int y,int l,int r){
        if(x>r||y<l) return 0;
        if(x>=l&&y<=r) return tree[k];
        if(tag[k]!=-1) update(k,x,y);
        int mid=x+y>>1;
        int a=query(ls,x,mid,l,r);
        int b=query(rs,mid+1,y,l,r);
        return a+b;
    }
    inline void change(int k,int x,int y,int l,int r,int val){
        if(x>r||y<l) return;
        if(x>=l&&y<=r){
            tag[k]=val;
            tree[k]=(y-x+1)*val;
            return;
        }
        if(tag[k]!=-1) update(k,x,y);
        int mid=x+y>>1;
        change(ls,x,mid,l,r,val);
        change(rs,mid+1,y,l,r,val);
        tree[k]=tree[ls]+tree[rs];
    }
    inline bool check(int x){
        int i,cnt,l,r;
        memset(tag,-1,sizeof(tag));
        build(1,1,n,x);
        for(i=1;i<=m;i++){
            l=op[i][1],r=op[i][2];
            cnt=query(1,1,n,l,r);
            if(op[i][0]){
                change(1,1,n,l,l+cnt-1,1);
                change(1,1,n,l+cnt,r,0);
            }
            else{
                change(1,1,n,r-cnt+1,r,1);
                change(1,1,n,l,r-cnt,0);
            }
        }
        return query(1,1,n,pos,pos);
    }
    int main()
    {
        int i,j,x,y,t,s,cnt;
        read(n),read(m);
        for(i=1;i<=n;i++) read(a[i]);
        for(i=1;i<=m;i++)
            read(op[i][0]),read(op[i][1]),read(op[i][2]);
        int L=1,R=n,ans,mid;
        read(pos);
        while(R>=L){
            mid=L+R>>1;
            if(check(mid)) L=mid+1,ans=mid;
            else R=mid-1;
        }
        printf("%d",ans);
    } 
  • 相关阅读:
    Bellman-Ford算法
    POJ 1990 MooFest
    POJ3067:Japan(树状数组求逆序对)
    树状数组求逆序对
    树状数组
    Is It A Tree?(hdu1325)
    强连通图 Tarjan算法
    UVALive
    UVALive
    Problem Statement
  • 原文地址:https://www.cnblogs.com/quitter/p/11674542.html
Copyright © 2011-2022 走看看