排序(bzoj 4552)

Description

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

,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排

序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q

位置上的数字。

Input

输入数据的第一行为两个整数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

Output

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

Sample Input

6 3

1 6 2 5 3 4

0 1 4

1 3 6

0 2 4

3

Sample Output

5

/*
    题解很神奇。
    二分答案k,那么就是要判断a[p]与k的大小关系。
    我们把序列变成0/1序列,0代表该位置的数小于k,1代表大于等于k,对于升降序操作,
    用线段树维护就可以了,最后判断一下。
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 30010
using namespace std;
int a[N],b[N][3],n,m,p;
int sum[N*4],tag[N*4];
void push_up(int k){
    sum[k]=sum[k*2]+sum[k*2+1];
}
void push_down(int k,int l,int r){
    if(tag[k]==-1) return;
    int mid=l+r>>1;
    tag[k*2]=tag[k*2+1]=tag[k];
    sum[k*2]=(mid-l+1)*tag[k];
    sum[k*2+1]=(r-mid)*tag[k];
    tag[k]=-1;
}
void change(int k,int l,int r,int x,int y,int val){
    if(x>y) return;
    if(l>=x&&r<=y){
        sum[k]=(r-l+1)*val;
        tag[k]=val;
        return;
    }
    push_down(k,l,r);
    int mid=l+r>>1;
    if(x<=mid) change(k*2,l,mid,x,y,val);
    if(y>mid) change(k*2+1,mid+1,r,x,y,val);
    push_up(k);
}
int query(int k,int l,int r,int x,int y){
    if(l>=x&&r<=y) return sum[k];
    push_down(k,l,r);
    int mid=l+r>>1,tot=0;
    if(x<=mid) tot+=query(k*2,l,mid,x,y);
    if(y>mid) tot+=query(k*2+1,mid+1,r,x,y);
    return tot;
}
bool check(int mid){
    memset(tag,-1,sizeof(tag));
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++) change(1,1,n,i,i,a[i]>=mid);
    for(int i=1;i<=m;i++){
        int t=query(1,1,n,b[i][1],b[i][2]);
        if(!b[i][0]){
            change(1,1,n,b[i][1],b[i][2]-t,0);
            change(1,1,n,b[i][2]-t+1,b[i][2],1);
        }
        else {
            change(1,1,n,b[i][1],b[i][1]+t-1,1);
            change(1,1,n,b[i][1]+t,b[i][2],0);
        }
    }
    int t=query(1,1,n,p,p);
    return t;
}
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",&b[i][0],&b[i][1],&b[i][2]);
    scanf("%d",&p);
    int l=0,r=n,ans;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)) l=mid+1,ans=mid;
        else r=mid-1;
    }
    printf("%d",ans);
    return 0;
}
时间: 2024-10-10 20:24:48

排序(bzoj 4552)的相关文章

[BZOJ] 4552: [Tjoi2016&amp;Heoi2016]排序 #二分+线段树+算法设计策略

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1451  Solved: 734[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,r

bzoj 4552 [Tjoi2016&amp;Heoi2016]排序——二分答案

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 二分答案,把 >= mid 的设成1.< mid 的设成0,之后排序就变成区间赋值了. #include<cstdio> #include<cstring> #include<algorithm> #define ls Ls[cr] #define rs Rs[cr] using namespace std; const int N=1e5+5,

bzoj 4552: [Tjoi2016&amp;Heoi2016]排序

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

BZOJ 4552 排序

省选TM都能有BC原题? ... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 #define inf 1000000007 using namespace std; int n,m,a[maxn],l=inf,r=0,mi,q; int ls[maxn<<2],rs[maxn<<2],lazy

(拓扑排序) bzoj 1040

4010: [HNOI2015]菜肴制作 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 498  Solved: 275[Submit][Status][Discuss] Description 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予 1到N的顺序编号,预估质量最高的菜肴编号为1.由于菜肴之间口味搭配的问题, 某些菜肴必须在另一些菜肴之前制作,具体的,一

bzoj 4552

二分 + 线段树二分一个值 x, 讲原序列转化为01序列1表示该数>x, 0表示改数<x;线段树维护区间和进行判断 #include <bits/stdc++.h> const int N = 1e5 + 10; #define gc getchar() int n, m, Q; int A[N], B[N]; int S[N << 2], W[N << 2], F[N << 2]; int opt[N], lask[N], rask[N]; i

【刷题记录】杂题记录

1.[bzoj 4552][Tjoi2016&Heoi2016]排序 题意:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序.排序分为两种:(0,l,r)表示将区间[l,r]的数字升序排序:(1,l,r)表示将区间[l,r]的数字降序排序.最后询问第q位置上的数字. 分析:二分答案,将所有值小于等于当前值的数赋为0,其余赋为1.利用线段树可以通过统计区间内数字1的个数来使当前区间有序.进行m次局部排序后可以得到答案与当前值的大小关系,满足可二分性. 1 #include<cstd

4552: [Tjoi2016&amp;Heoi2016]排序

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

BZOJ 2080: [Poi2010]Railway 双栈排序

2080: [Poi2010]Railway Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 140  Solved: 35[Submit][Status][Discuss] Description 一个铁路包含两个侧线1和2,右边由A进入,左边由B出去(看下面的图片) 有n个车厢在通道A上,编号为1到n,它们被安排按照要求的顺序(a1,a2,a3,a4....an)进入侧线,进去还要出来,它们要按照编号顺序(1,2,3,4,5....n)从通道B