zoukankan      html  css  js  c++  java
  • [HEOI2016/TJOI2016]排序

    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    (luogu数据,30000)

    题解:

    确实开始比较没有思路。

    不像某JZOJ模拟题,可以线段树维护区间内每个字符的个数。

    但是这一共30000个字符啊!!!没办法乖乖排序

    发现,突破口是,最后只要知道q位置是什么就可以!

    神仙思路:

    我们二分一个q位置的值mid,把所有的小于的值的位置赋值为1,否则就是0

    然后循环m,0/1排序就比较方便了。线段树,找到区间有多少个1,多少个0,把所有的0放左边,然后放1(降序的话反过来)

    最后,如果q位置是1,那么ans=mid,r=mid-1;

    如果q位置是0,那么l=mid+1

    复杂度O(nlog^2n)

    代码:

    #include<bits/stdc++.h>
    #define mid ((l+r)>>1)
    using namespace std;
    const int N=30000+4;
    int a[N];
    int b[N];
    int n,m;
    struct node{
        int sum;
        int ch;
    }t[4*N];
    int q[N][3];
    int pos;
    void pushdown(int x,int l,int r){
        if(t[x].ch==-1) return;
        t[x<<1].ch=t[x].ch;
        t[x<<1|1].ch=t[x].ch;
        t[x<<1].sum=t[x].ch*(mid-l+1);
        t[x<<1|1].sum=t[x].ch*(r-mid);
        t[x].ch=-1;
    }
    void build(int x,int l,int r){
        if(l==r){
            t[x].ch=-1;
            t[x].sum=b[l];
            return;
        }
        t[x].ch=-1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
    }
    int query(int x,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            return t[x].sum;
        }
        pushdown(x,l,r);
        int ret=0;
        if(L<=mid) ret+=query(x<<1,l,mid,L,R);
        if(mid<R) ret+=query(x<<1|1,mid+1,r,L,R);
        return ret;
    }
    void chan(int x,int l,int r,int L,int R,int c){
        if(L<=l&&r<=R){
            t[x].ch=c;
            t[x].sum=(r-l+1)*c;
            return;
        }
        pushdown(x,l,r);
        if(L<=mid) chan(x<<1,l,mid,L,R,c);
        if(mid<R) chan(x<<1|1,mid+1,r,L,R,c);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
    }
    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][0],&q[i][1],&q[i][2]);
        }
        scanf("%d",&pos);
        int l=1,r=n;
        int ans;
        while(l<=r){
            int MID=(l+r)>>1;
            
            for(int i=1;i<=n;i++){
                if(a[i]>=MID) b[i]=1;
                else b[i]=0;
                //cout<<b[i]<<" ";
            }//cout<<endl;
            build(1,1,n);
            
            //cout<<l<<" "<<r<<" mid "<<MID<<endl;
            for(int i=1;i<=m;i++){
                //cout<<i<<" "<<q[i][1]<<" "<<q[i][2]<<endl;
                
                int sum1=query(1,1,n,q[i][1],q[i][2]);
                int sum0=q[i][2]-q[i][1]+1-sum1;
                
                //cout<<" sum "<<sum1<<" "<<sum0<<endl;            
                if(q[i][0]){//down
                    chan(1,1,n,q[i][1],q[i][1]+sum1-1,1);
                    chan(1,1,n,q[i][1]+sum1,q[i][2],0);
                }
                else{//up
                    chan(1,1,n,q[i][1],q[i][1]+sum0-1,0);
                    chan(1,1,n,q[i][1]+sum0,q[i][2],1);
                }
            }
            
            int lp=query(1,1,n,pos,pos);
            if(lp==1) ans=MID,l=MID+1;
            else r=MID-1;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    scala言语基础学习七
    scala言语基础学习六
    scala言语基础学习五
    scala言语基础学习四
    scala言语基础学习三(面向对象编程)
    scala言语基础学习三
    scala言语基础学习二
    scala言语基础学习
    并发编程实战的阅读(锁的重入)
    数据库必会必知 之 SQL四种语言:DDL DML DCL TCL(转)
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9601189.html
Copyright © 2011-2022 走看看