1. 程式人生 > >【HEOI2016/TJOI2016】排序(二份答案+線段樹)

【HEOI2016/TJOI2016】排序(二份答案+線段樹)

傳送門

一道思路很好的題

首先考慮如果是0/1串該怎麼做

我們發現我們可以在 O ( l o g n )

O(log_n) 的時間完成對這樣一個序列的排序

q u e r y query 出這個區間的和 t

o t tot

那麼顯然所有的 1 1 都到一邊去了 0 0

到另一邊去了

那麼 l ( l + t o t 1 ) l-(l+tot-1) 這個區間就都是 0 0 ,剩下的都是1,那我們打一個區間覆蓋標記就可以了

考慮到題目中給的是一個 1 1 ~ n n 的全排列

所以我們可以直接二分這個位置是什麼數

那麼把整個序列中大於他的設為1,小於的設為0

那麼就變成了上面說的0/1串問題

暴力 O ( m l o g n ) O(mlog_n) 做一遍之後看 q q 這個位置上是0還是1

0就把上界調低,1就把下界調高

正確的就不用證明了吧

結果半天過不了發現二分和線段樹巨集衝突了
程式碼:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
#define lc (u<<1)
#define rc ((u<<1)+1)
#define mid ((l+r)>>1)
const int N=100005;
int op[N],L[N],k,R[N],val[N],tr[N<<2],mark[N<<2],n,m,a[N];
inline void pushup(int u){tr[u]=tr[lc]+tr[rc];}
inline void buildtree(int u,int l,int r){
    mark[u]=-1;
    if(l==r){tr[u]=a[l];return;}
    buildtree(lc,l,mid);
    buildtree(rc,mid+1,r);
    pushup(u);
}
inline void pushdown(int u,int p,int t){
    if(mark[u]==-1)return;
    mark[lc]=mark[rc]=mark[u];
    tr[lc]=mark[u]*p,tr[rc]=mark[u]*t;
    mark[u]=-1;
}
inline void update(int u,int l,int r,int st,int des,int k){
    if(des<l||r<st)return;
    if(l>=st&&r<=des){
        tr[u]=k*(r-l+1);
        mark[u]=k;return;
    }
    pushdown(u,mid-l+1,r-mid);
    update(lc,l,mid,st,des,k);
    update(rc,mid+1,r,st,des,k);
    pushup(u);
}
inline int query(int u,int l,int r,int st,int des){
    if(l>des||r<st)return 0;
    if(st<=l&&r<=des)return tr[u];
    pushdown(u,mid-l+1,r-mid);
    int ans=0;
    ans+=query(lc,l,mid,st,des);
    ans+=query(rc,mid+1,r,st,des);
    return ans;
}
inline bool check(int v){
    for(int i=1;i<=n;i++){
        if(val[i]>=v)a[i]=1;
        else a[i]=0;
    }
    buildtree(1,1,n);
    for(int i=1;i<=m;i++){
        int l=L[i],r=R[i];
        if(op[i]){
            int tmp=query(1,1,n,l,r);
            update(1,1,n,l,l+tmp-1,1);
            update(1,1,n,l+tmp,r,0);
        }
        else{
            int tmp=query(1,1,n,l,r);
            update(1,1,n,l,r-tmp,0);
            update(1,1,n,r-tmp+1,r,1);
        }
    }
    return query(1,1,n,k,k);
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)val[i]=read();
    for(int i=1;i<=m;i++)op[i]=read(),L[i]=read(),R[i]=read();
    k=read();
    int A=1,B=n,ans=0;
    while(A<=B){
        int py=(A+B)>>1;
        if(check(py))A=py+1,ans=py;
        else B=py-1;
    }
    cout<<ans;
}