bzoj千题计划128:bzoj4552: [Tjoi2016&Heoi2016]排序
Posted 日拱一卒 功不唐捐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj千题计划128:bzoj4552: [Tjoi2016&Heoi2016]排序相关的知识,希望对你有一定的参考价值。
http://www.lydsy.com/JudgeOnline/problem.php?id=4552
二分答案
把>=mid 的数看做1,<mid 的数看做0
这样升序、降序排列相当于区间查询0,1 的个数,区间覆盖0,1
线段树即可完成
查询给定位置p
如果=1,说明p位置的数>=mid ,上调下界
如果=0,说明p位置的数<mid,下调上界
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 100001 int n,m,p; int a[N],MID; int sum0[N<<2],sum1[N<<2],flag[N<<2]; int tot0,tot1; struct node { int ty,l,r; }e[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); } } void build(int k,int l,int r) { sum0[k]=sum1[k]=0; flag[k]=-1; if(l==r) { if(a[l]>=MID) sum1[k]++; else sum0[k]++; return; } int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); sum0[k]=sum0[k<<1]+sum0[k<<1|1]; sum1[k]=sum1[k<<1]+sum1[k<<1|1]; } void down(int k,int l,int mid,int r) { if(!flag[k]) { sum0[k<<1]=mid-l+1; sum1[k<<1]=0; sum0[k<<1|1]=r-mid; sum1[k<<1|1]=0; } else { sum1[k<<1]=mid-l+1; sum0[k<<1]=0; sum1[k<<1|1]=r-mid; sum0[k<<1|1]=0; } flag[k<<1]=flag[k<<1|1]=flag[k]; flag[k]=-1; } void query(int k,int l,int r,int opl,int opr) { if(l>=opl && r<=opr) { tot0+=sum0[k]; tot1+=sum1[k]; return; } int mid=l+r>>1; if(flag[k]!=-1) down(k,l,mid,r); if(opl<=mid) query(k<<1,l,mid,opl,opr); if(opr>mid) query(k<<1|1,mid+1,r,opl,opr); } void change(int k,int l,int r,int opl,int opr,int ty) { if(l>=opl && r<=opr) { if(!ty) { sum0[k]=r-l+1; sum1[k]=0; } else { sum0[k]=0; sum1[k]=r-l+1; } flag[k]=ty; return; } int mid=l+r>>1; if(flag[k]!=-1) down(k,l,mid,r); if(opl<=mid) change(k<<1,l,mid,opl,opr,ty); if(opr>mid) change(k<<1|1,mid+1,r,opl,opr,ty); sum0[k]=sum0[k<<1]+sum0[k<<1|1]; sum1[k]=sum1[k<<1]+sum1[k<<1|1]; } int ask(int k,int l,int r,int pos) { if(l==r) return sum1[k]; int mid=l+r>>1; if(flag[k]!=-1) down(k,l,mid,r); if(pos<=mid) return ask(k<<1,l,mid,pos); return ask(k<<1|1,mid+1,r,pos); } bool check(int mid) { MID=mid; build(1,1,n); for(int i=1;i<=m;++i) { tot0=tot1=0; query(1,1,n,e[i].l,e[i].r); if(!e[i].ty) { if(tot0) change(1,1,n,e[i].l,e[i].l+tot0-1,0); if(tot1) change(1,1,n,e[i].r-tot1+1,e[i].r,1); } else { if(tot1) change(1,1,n,e[i].l,e[i].l+tot1-1,1); if(tot0) change(1,1,n,e[i].r-tot0+1,e[i].r,0); } } return ask(1,1,n,p); } int main() { read(n); read(m); for(int i=1;i<=n;++i) read(a[i]); for(int i=1;i<=m;++i) read(e[i].ty),read(e[i].l),read(e[i].r); read(p); int l=1,r=n,mid,ans; while(l<=r) { mid=MID=l+r>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } cout<<ans; }
4552: [Tjoi2016&Heoi2016]排序
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1478 Solved: 748
[Submit][Status][Discuss]
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
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
Sample Output
5
以上是关于bzoj千题计划128:bzoj4552: [Tjoi2016&Heoi2016]排序的主要内容,如果未能解决你的问题,请参考以下文章
bzoj千题计划118:bzoj1028: [JSOI2007]麻将
bzoj千题计划144:bzoj1176: [Balkan2007]Mokia