zoukankan      html  css  js  c++  java
  • loj #2055. 「TJOI / HEOI2016」排序

    #2055. 「TJOI / HEOI2016」排序

     

    题目描述

    在 2016 年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。

    这个难题是这样子的:给出一个 1 11 到 n nn 的全排列,现在对这个全排列序列进行 m mm 次局部排序,排序分为两种:

    1. (0,l,r) (0, l, r)(0,l,r) 表示将区间 [l,r] [l, r][l,r] 的数字升序排序
    2. (1,l,r) (1, l ,r)(1,l,r) 表示将区间 [l,r] [l, r][l,r] 的数字降序排序

    排序后询问第 q qq 位置上的数字。

    输入格式

    输入数据的第一行为两个整数 n nn 和 m mm。n nn 表示序列的长度,m mm 表示局部排序的次数 (1≤n,m≤1051 leq n, m leq 10^51n,m105​​)。
    第二行为 n nn 个整数,表示 1 11 到 n nn 的一个全排列。
    接下来输入 m mm 行,每一行有三个整数 op,l,r ext{op}, l, rop,l,r, op ext{op}op 为 0 代表升序排序,op ext{op}op 为 1 代表降序排序, l,rl, rl,r 表示排序的区间。
    最后输入一个整数 qqq,qqq 表示排序完之后询问的位置,1≤q≤n1 leq q leq n1qn。

    输出格式

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

    样例

    样例输入

    6 3
    1 6 2 5 3 4
    0 1 4
    1 3 6
    0 2 4
    3

    样例输出

    5

    二分p位置上的值

    小于p的为0,大于p的为1

     线段树支持区间修改,查询区间0的个数

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100010
    using namespace std;
    int a[maxn],n,m;
    bool cmp(int x,int y){return x>y;}
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int op,l,r;
        while(m--){
            scanf("%d%d%d",&op,&l,&r);
            if(op==1) sort(a+l,a+r+1,cmp);
            if(op==0) sort(a+l,a+r+1);
        }
        int q;scanf("%d",&q);
        cout<<a[q];
    } 
    80分 暴力
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 100010
    using namespace std;
    int a[maxn],sum[maxn*5],set[maxn*5],ask[maxn][3];
    bool bz[maxn*5];
    int t,n,m,p;
    void mark(int k,int l,int r,int v){
        sum[k]=(v?0:r-l+1);
        set[k]=v;
        bz[k]=1;
    }
    void pushdown(int k,int l,int r){
        int mid=(l+r)>>1;
        if(bz[k]){
            mark(k<<1,l,mid,set[k]);
            mark(k<<1|1,mid+1,r,set[k]);
            bz[k]=0;
        }
    }
    void modify(int k,int l,int r,int opl,int opr,int v){
        if(opl>opr)return;
        if(l==opl&&r==opr){mark(k,l,r,v);return;}
        pushdown(k,l,r);
        int mid=(l+r)>>1;
        if(opr<=mid)modify(k<<1,l,mid,opl,opr,v);
        else if(opl>mid)modify(k<<1|1,mid+1,r,opl,opr,v);
        else modify(k<<1,l,mid,opl,mid,v),modify(k<<1|1,mid+1,r,mid+1,opr,v);
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    int query(int k,int l,int r,int opl,int opr){
        if(l>=opl&&r<=opr)return sum[k];
        pushdown(k,l,r);
        int mid=(l+r)>>1,res=0;
        if(opl<=mid)res+=query(k<<1,l,mid,opl,opr);
        if(opr>mid)res+=query(k<<1|1,mid+1,r,opl,opr);
        return res;
    }
    bool check(int x){
        for(int i=1;i<=n;i++)
            if(a[i]<x)modify(1,1,n,i,i,0);
            else modify(1,1,n,i,i,1);
        for(int i=1;i<=m;i++){
            t=query(1,1,n,ask[i][1],ask[i][2]);
            if(ask[i][0]){
                modify(1,1,n,ask[i][1],ask[i][2]-t,1);
                modify(1,1,n,ask[i][2]-t+1,ask[i][2],0);
            }
            else {
                modify(1,1,n,ask[i][1],ask[i][1]+t-1,0);
                modify(1,1,n,ask[i][1]+t,ask[i][2],1);
            }
        }
        return !query(1,1,n,p,p);
    }
    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",&ask[i][0],&ask[i][1],&ask[i][2]);
        scanf("%d",&p);
        int l=1,r=n,ans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid))l=mid+1,ans=mid;
            else r=mid-1;
        }
        printf("%d",ans);
    }
    100分 线段树+二分答案
  • 相关阅读:
    PHP5中PDO的简单使用
    Apache中设置默认首页的方法
    PHP数组读取的循环操作
    header("Location:login.php")应该注意的几个问题
    纯JavaScript实现弹出选择第几个单选按钮
    PHP关于错误抑制符@的使用
    CSS盒子模型
    Appache中的ServerAlias
    PHP move_uploaded_file() 函数 定义和用法
    PHP ob_start() 函数介绍
  • 原文地址:https://www.cnblogs.com/thmyl/p/8914961.html
Copyright © 2011-2022 走看看