在 2016 2016 2016 年,佳媛姐姐喜欢上了数字序列。因而她经常研究关于序列的一些奇奇怪怪的问题,现在她在研究一个难题,需要你来帮助她。
这个难题是这样子的:给出一个 1 1 1 到 n n n 的排列,现在对这个排列序列进行 m m m 次局部排序,排序分为两种:
0 l r
表示将区间 [ l , r ] [l,r] [l,r] 的数字升序排序1 l r
表示将区间 [ l , r ] [l,r] [l,r] 的数字降序排序注意,这里是对下标在区间 [ l , r ] [l,r] [l,r] 内的数排序。
最后询问第 q q q 位置上的数字。
输入数据的第一行为两个整数 n n n 和 m m m, n n n 表示序列的长度, m m m 表示局部排序的次数。
第二行为 n n n 个整数,表示 1 1 1 到 n n n 的一个排列。
接下来输入 m m m 行,每一行有三个整数 op , l , r \text{op},l,r op,l,r, op \text{op} op 为 0 0 0 代表升序排序, op \text{op} op 为 1 1 1 代表降序排序, l , r l,r l,r 表示排序的区间。
最后输入一个整数 q q q,表示排序完之后询问的位置
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第 q q q 位置上的数字。
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
5
河北省选2016第一天第二题。
对于 30 % 30\% 30% 的数据, n , m ≤ 1000 n,m\leq 1000 n,m≤1000
对于 100 % 100\% 100% 的数据, n , m ≤ 1 0 5 n,m\leq 10^5 n,m≤105, 1 ≤ q ≤ n 1\leq q\leq n 1≤q≤n
首先我们要求出当前区间有几个1,设cnt
这样,排序问题就被转化为了区间修改,区间查询,单点查询问题。
bool check(int md){
build(1,1,n,md);
for(int i=1;i<=m;i++){
int cnt=query(1,1,n,l[i],r[i]);
if(op[i]==0){
update(1,1,n,l[i],r[i]-cnt,0);
update(1,1,n,r[i]-cnt+1,r[i],1);
}
else if(op[i]==1){
update(1,1,n,l[i]+cnt,r[i],0);
update(1,1,n,l[i],l[i]+cnt-1,1);
}
}
return query_point(1,1,n,q);
}
while(ll<=rr){
int mmid=(ll+rr)>>1;
if(check(mmid)){
ll=mmid+1;
}
else {
rr=mmid-1;
}
}
cout<<rr<<endl;
经过元素与mid比较,建树,操作后再次查询q,若q为1,说明当前数可行,更新L为mid+1,反正更新R为mid-1
bool check(int md){
build(1,1,n,md);
for(int i=1;i<=m;i++){
int cnt=query(1,1,n,l[i],r[i]);
if(op[i]==0){
update(1,1,n,l[i],r[i]-cnt,0);
update(1,1,n,r[i]-cnt+1,r[i],1);
}
else if(op[i]==1){
update(1,1,n,l[i]+cnt,r[i],0);
update(1,1,n,l[i],l[i]+cnt-1,1);
}
}
return query_point(1,1,n,q);
}
#include
using namespace std;
const int N=1e6+888;
int n,m,q,l[N],r[N],op[N];
int sm[N<<2],tag[N<<2],a[N];
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
#define int long long int
void pushup(int x){
sm[x]=sm[lc(x)]+sm[rc(x)];
}
void build(int x,int l,int r,int midd){
tag[x]=0;
if(l==r){
if(a[l]<midd){
sm[x]=0;
}
else sm[x]=1;
return;
}
int mid=(l+r)>>1;
build(lc(x),l,mid,midd);
build(rc(x),mid+1,r,midd);
pushup(x);
}
void cover(int x,int l,int r,int ad){
sm[x]+=(r-l+1)*ad;
if(ad==1) tag[x]=ad;
else tag[x]=-1;
}
void pushdown(int x,int l,int r){
if(!tag[x])return;
int mid=(l+r)>>1;
// cover(lc(x),l,mid,tag[x]);
// cover(rc(x),mid+1,r,tag[x]);
tag[lc(x)]=tag[rc(x)]=tag[x];
if(tag[x]==1){
sm[lc(x)]=mid-l+1;
sm[rc(x)]=r-mid;
}
else {
sm[lc(x)]=sm[rc(x)]=0;
}
tag[x]=0;
}
void update(int x,int l,int r,int L,int R,int ad){
if(l>R||r<L)return;
if(l>=L&&R>=r){
//cover(x,l,r,ad);
sm[x]=(r-l+1)*ad;
if(ad==1){
tag[x]=1;
}
else tag[x]=-1;
return;
}
pushdown(x,l,r);
int mid=(l+r)>>1;
update(lc(x),l,mid,L,R,ad);
update(rc(x),mid+1,r,L,R,ad);
pushup(x);
}
int query(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(l>=L&&R>=r){
return sm[x];
}
int mid=(l+r)>>1;
pushdown(x,l,r);
return query(lc(x),l,mid,L,R)+query(rc(x),mid+1,r,L,R);
}
int query_point(int x,int l,int r,int xy){
// if(l>xy||r
if(l==r&&l==xy){
return sm[x];
}
int mid=(l+r)>>1;
pushdown(x,l,r);
if(xy<=mid) return query_point(lc(x),l,mid,xy);
else return query_point(rc(x),mid+1,r,xy);
}
bool check(int md){
build(1,1,n,md);
for(int i=1;i<=m;i++){
int cnt=query(1,1,n,l[i],r[i]);
if(op[i]==0){
update(1,1,n,l[i],r[i]-cnt,0);
update(1,1,n,r[i]-cnt+1,r[i],1);
}
else if(op[i]==1){
update(1,1,n,l[i]+cnt,r[i],0);
update(1,1,n,l[i],l[i]+cnt-1,1);
}
}
return query_point(1,1,n,q);
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
cin>>op[i]>>l[i]>>r[i];
}
cin>>q;
int ll=0,rr=1999990;
while(ll<=rr){
int mmid=(ll+rr)>>1;
if(check(mmid)){
ll=mmid+1;
}
else {
rr=mmid-1;
}
}![请添加图片描述](https://img-blog.csdnimg.cn/95443962d73e4da588fa06edf7ca3579.png)
cout<<rr<<endl;
return 0;
}