zoukankan      html  css  js  c++  java
  • BZOJ4552 [Tjoi2016&Heoi2016]排序

    1. Description

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

    2. Input

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

    3. Output

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

    4. Sample Input

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

    5. Sample Output

    5

    5. 思路

    离线询问之后二分答案。使用线段树维护,将大于等于二分的$mid$值的数视为1,否则为0,这样查询的序列就变成了一个01序列。此时一个区间被排序后会是一段全是0一段全是1的状态,因此排序只需要查询区间的1的个数(这里也就是区间求和)然后进行区间修改就可以了。最后判断一下$q$位置的值是否为1(不然就小于$mid$了),继续二分直到得到答案。

    6. 代码

    主要来自http://blog.csdn.net/werkeytom_ftd/article/details/51366237

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <sstream>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #define the_best_pony "Rainbow Dash"
    
    using namespace std;
    const int maxn=100000+10;
    
    int a[maxn],sum[maxn*5],set[maxn*5],ask[maxn][3];
    bool bz[maxn*5];
    int i,j,k,l,r,mid,t,n,m,p;
    
    void mark(int p,int l,int r,int v){
        sum[p]=(v?0:r-l+1);
        set[p]=v;
        bz[p]=1;
        return;
    }
    
    void down(int p,int l,int r){
        int mid=(l+r)/2;
        if(bz[p]){
            mark(p*2,l,mid,set[p]);
            mark(p*2+1,mid+1,r,set[p]);
            bz[p]=0;
        }
        return;
    }
    
    void change(int p,int l,int r,int a,int b,int v){
        if(a>b) return;
        if(l==a&&r==b){
            mark(p,l,r,v);
            return;
        }
        down(p,l,r);
        int mid=(l+r)/2;
        if(b<=mid) change(p*2,l,mid,a,b,v);
        else if(a>mid) change(p*2+1,mid+1,r,a,b,v);
        else change(p*2,l,mid,a,mid,v),change(p*2+1,mid+1,r,mid+1,b,v);
        sum[p]=sum[p*2]+sum[p*2+1];
        return;
    }
    
    int query(int p,int l,int r,int a,int b){
        if(l==a&&r==b) return sum[p];
        down(p,l,r);
        int mid=(l+r)/2;
        if(b<=mid) return query(p*2,l,mid,a,b);
        else if(a>mid) return query(p*2+1,mid+1,r,a,b);
        else return query(p*2,l,mid,a,mid)+query(p*2+1,mid+1,r,mid+1,b);
    }
    
    bool check(int x){
        for(int i=1;i<=n;i++) 
            if(a[i]<x) change(1,1,n,i,i,0);
    		else change(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]){
                change(1,1,n,ask[i][1],ask[i][2]-t,1);
                change(1,1,n,ask[i][2]-t+1,ask[i][2],0);
            }
            else{
                change(1,1,n,ask[i][1],ask[i][1]+t-1,0);
                change(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);
        l=1;r=n;
        while(l<r){
            mid=(l+r+1)/2;
            if(check(mid)) l=mid;
    		else r=mid-1;
        }
        printf("%d
    ",l);
        return 0;
    }
  • 相关阅读:
    C++之STL一般总结
    QT学习第2天
    Linux下Awk详解(转载)
    Mac下开启FTPserver
    Mac下QT错误,Xcode配置解决办法
    C++之STL
    关于Java自动拆箱装箱中的缓存问题
    二分查找
    冒泡排序及优化
    Java中String常用方法总结
  • 原文地址:https://www.cnblogs.com/blogo-de-vk/p/bzoj4552.html
Copyright © 2011-2022 走看看