[HEOI2016/TJOI2016]排序

Posted miracevin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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;
}

 

以上是关于[HEOI2016/TJOI2016]排序的主要内容,如果未能解决你的问题,请参考以下文章

[HEOI2016/TJOI2016]排序 解题报告

「Luogu2824」[HEOI2016/TJOI2016]排序

[HEOI2016/TJOI2016]排序

[HEOI2016/TJOI2016]排序

HEOI2016/TJOI2016 排序

[HEOI2016/TJOI2016]排序