loj #2055. 「TJOI / HEOI2016」排序
#2055. 「TJOI / HEOI2016」排序
题目描述
在 2016 年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。
这个难题是这样子的:给出一个 1 11 到 n nn 的全排列,现在对这个全排列序列进行 m mm 次局部排序,排序分为两种:
- (0,l,r) (0, l, r)(0,l,r) 表示将区间 [l,r] [l, r][l,r] 的数字升序排序
- (1,l,r) (1, l ,r)(1,l,r) 表示将区间 [l,r] [l, r][l,r] 的数字降序排序
排序后询问第 q qq 位置上的数字。
输入格式
输入数据的第一行为两个整数 n nn 和 m mm。n nn 表示序列的长度,m mm 表示局部排序的次数 (1≤n,m≤1051 \leq n, m \leq 10^51≤n,m≤105)。
第二行为 n nn 个整数,表示 1 11 到 n nn 的一个全排列。
接下来输入 m mm 行,每一行有三个整数 op,l,r\text{op}, l, rop,l,r, op\text{op}op 为 0
代表升序排序,op\text{op}op 为 1
代表降序排序, l,rl, rl,r 表示排序的区间。
最后输入一个整数 qqq,qqq 表示排序完之后询问的位置,1≤q≤n1 \leq q \leq n1≤q≤n。
输出格式
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第 q qq 位置上的数字。
样例
样例输入
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
样例输出
5
二分p位置上的值
小于p的为0,大于p的为1
线段树支持区间修改,查询区间0的个数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100010 using namespace std; int a[maxn],n,m; bool cmp(int x,int y){return x>y;} int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); int op,l,r; while(m--){ scanf("%d%d%d",&op,&l,&r); if(op==1) sort(a+l,a+r+1,cmp); if(op==0) sort(a+l,a+r+1); } int q;scanf("%d",&q); cout<<a[q]; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #define maxn 100010 using namespace std; int a[maxn],sum[maxn*5],set[maxn*5],ask[maxn][3]; bool bz[maxn*5]; int t,n,m,p; void mark(int k,int l,int r,int v){ sum[k]=(v?0:r-l+1); set[k]=v; bz[k]=1; } void pushdown(int k,int l,int r){ int mid=(l+r)>>1; if(bz[k]){ mark(k<<1,l,mid,set[k]); mark(k<<1|1,mid+1,r,set[k]); bz[k]=0; } } void modify(int k,int l,int r,int opl,int opr,int v){ if(opl>opr)return; if(l==opl&&r==opr){mark(k,l,r,v);return;} pushdown(k,l,r); int mid=(l+r)>>1; if(opr<=mid)modify(k<<1,l,mid,opl,opr,v); else if(opl>mid)modify(k<<1|1,mid+1,r,opl,opr,v); else modify(k<<1,l,mid,opl,mid,v),modify(k<<1|1,mid+1,r,mid+1,opr,v); sum[k]=sum[k<<1]+sum[k<<1|1]; } int query(int k,int l,int r,int opl,int opr){ if(l>=opl&&r<=opr)return sum[k]; pushdown(k,l,r); int mid=(l+r)>>1,res=0; if(opl<=mid)res+=query(k<<1,l,mid,opl,opr); if(opr>mid)res+=query(k<<1|1,mid+1,r,opl,opr); return res; } bool check(int x){ for(int i=1;i<=n;i++) if(a[i]<x)modify(1,1,n,i,i,0); else modify(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]){ modify(1,1,n,ask[i][1],ask[i][2]-t,1); modify(1,1,n,ask[i][2]-t+1,ask[i][2],0); } else { modify(1,1,n,ask[i][1],ask[i][1]+t-1,0); modify(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); int l=1,r=n,ans=0; while(l<=r){ int mid=(l+r)>>1; if(check(mid))l=mid+1,ans=mid; else r=mid-1; } printf("%d",ans); }