zoukankan      html  css  js  c++  java
  • [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);
    }
    
    
  • 相关阅读:
    【linux高级程序设计】(第八章)进程管理与程序开发 3
    【linux高级程序设计】(第八章)进程管理与程序开发 2
    【linux高级程序设计】(第八章)进程管理与程序开发 1
    【linux高级程序设计】(第七章)终端及串口编程 未完成
    【剑指offer】数值的整数次方
    【剑指offer】二进制中1的个数
    【剑指offer】替换空格
    Android 最新控件 Toolbar
    IE 扩展调用主窗体中的函数
    JAVA程序设计(12.3)---- 监听器0基础应用:五子棋
  • 原文地址:https://www.cnblogs.com/BruceW/p/12193650.html
Copyright © 2011-2022 走看看