[HEOI2016/TJOI2016]排序 解题报告

Posted brucew-07

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HEOI2016/TJOI2016]排序 解题报告相关的知识,希望对你有一定的参考价值。

[HEOI2016/TJOI2016]排序

题意

给出一个大小为 (n) 的排列, 对这个排列进行 (m) 次操作, 操作分为以下两种,

  1. 0 l r 表示将区间 ([l,r]) 的数升序排序.
  2. 1 l r 表示将区间 ([l,r]) 的数降序排序.

询问 (m) 次操作后下标为 (q) 的数字.


思路

不看题解打死也想不出来系列

考虑二分答案.

设当前二分的答案为 (mid), 把原排列中 大于等于 (mid) 的数标记为 (1), 小于 (mid) 的数标记为 (0).

对于这样的一个 (0,1) 串, 我们可以用线段树实现 (log n) 的排序.

若当前区间 (l,r) 的区间和为 (num), 那么就代表有 (num)(1)(r-l+1-num)(0), 然后我们只需按要求把区间的前部分设为 (0)(1), 后部分设为另一个数就行了.

最后判断一下下标为 (q) 的数字是否为 (1), 若是, 则另 (l=mid+1), 否则另 (r=mid-1).


代码

#include<bits/stdc++.h>
using namespace std;
const int _=1e5+7;
const int __=4e5+7;
int n,m,q,a[_],sum[__],tag[__],ans,x;
struct oper{
  int l,r,ty;
}op[_];
void init(){
  cin>>n>>m;
  for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
  for(int i=1;i<=m;i++)
    scanf("%d%d%d",&op[i].ty,&op[i].l,&op[i].r);
  cin>>q;
}
void build(int k,int l,int r){
  tag[k]=-1;
  if(l==r){ sum[k]= a[l]>=x; return; }
  int mid=(l+r)>>1;
  build(k<<1,l,mid);
  build(k<<1|1,mid+1,r);
  sum[k]=sum[k<<1]+sum[k<<1|1];
}
void upd(int k,int l,int r,bool w){
  sum[k]= w ?r-l+1 :0;
  tag[k]=w;
}
void psd(int k,int l,int r){
  if(tag[k]==-1) return;
  int mid=(l+r)>>1;
  upd(k<<1,l,mid,tag[k]);
  upd(k<<1|1,mid+1,r,tag[k]);
  tag[k]=-1;
}
void modify(int k,int l,int r,int x,int y,bool w){
  if(x>y) return;
  if(l>=x&&r<=y){ upd(k,l,r,w); return; }
  psd(k,l,r);
  int mid=(l+r)>>1;
  if(x<=mid) modify(k<<1,l,mid,x,y,w);
  if(y>mid) modify(k<<1|1,mid+1,r,x,y,w);
  sum[k]=sum[k<<1]+sum[k<<1|1];
}
int query(int k,int l,int r,int x,int y){
  if(l>=x&&r<=y) return sum[k];
  psd(k,l,r);
  int mid=(l+r)>>1,res=0;
  if(x<=mid) res+=query(k<<1,l,mid,x,y);
  if(y>mid) res+=query(k<<1|1,mid+1,r,x,y);
  return res;
}
bool judge(int mid){
  x=mid;
  build(1,1,n);
  for(int i=1;i<=m;i++){
    int num=query(1,1,n,op[i].l,op[i].r);
    if(!op[i].ty){
      modify(1,1,n,op[i].l,op[i].r-num,0);
      modify(1,1,n,op[i].r-num+1,op[i].r,1);
    }
    else{
      modify(1,1,n,op[i].l,op[i].l+num-1,1);
      modify(1,1,n,op[i].l+num,op[i].r,0);
    }
  }
  return query(1,1,n,q,q);
}
void run(){
  int l=1,r=n;
  while(l<=r){
    int mid=(l+r)>>1;
    if(judge(mid)){ ans=mid; l=mid+1; }
    else r=mid-1;
  }
}
int main(){
#ifndef ONLINE_JUDGE
  freopen("x.in","r",stdin);
  freopen("x.out","w",stdout);
#endif
  init();
  run();
  printf("%d
",ans);
}

以上是关于[HEOI2016/TJOI2016]排序 解题报告的主要内容,如果未能解决你的问题,请参考以下文章

「Luogu2824」[HEOI2016/TJOI2016]排序

HEOI2016/TJOI2016 排序

[HEOI2016/TJOI2016]排序

[HEOI2016/TJOI2016]排序

HEOI2016/TJOI2016 排序

[HEOI2016/TJOI2016]排序