1. 程式人生 > >【[HEOI2016/TJOI2016]排序】

【[HEOI2016/TJOI2016]排序】

巧妙思路題

有一個重要的思想就是把大於某一個數的數都變成\(1\),小於這個數的都變成\(0\),這個只有\(0\)\(1\)的序列就很好處理了

由於我們只需要在最後求出一個位置上是什麼數就可以了,所以我們沒有必要去精確算出來這一位上是什麼數

顯然是可以二分的

我們二分出來一個答案,我們按照上述的方法處理序列,之後由於只有\(0\)\(1\)了,我們可以直接用線段樹來完成排序

之後看看目標位置是\(0\)還是\(1\),可以得出當前這個答案是比真正的答案小還是大的判斷

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#define re register
#define maxn 30005
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
int l[maxn<<2],r[maxn<<2],tag[maxn<<2],d[maxn<<2];
int a[maxn],n,m;
int op[maxn],X[maxn],Y[maxn];
int q;
void build(int x,int y,int i)
{
    l[i]=x,r[i]=y;
    if(x==y) return;
    int mid=x+y>>1;
    build(x,mid,i<<1),build(mid+1,y,i<<1|1);
}
void Rebuild(int x,int y,int i,int val)
{
    tag[i]=-1;
    if(x==y)
    {
        if(a[x]>val) d[i]=1;
        else d[i]=0;
        return;
    }
    int mid=x+y>>1;
    Rebuild(x,mid,i<<1,val),Rebuild(mid+1,y,i<<1|1,val);
    d[i]=d[i<<1]+d[i<<1|1];
}
inline void pushdown(int i)
{
    if(tag[i]==-1) return;
    tag[i<<1]=tag[i];
    tag[i<<1|1]=tag[i];
    d[i<<1]=(r[i<<1]-l[i<<1]+1)*tag[i];
    d[i<<1|1]=(r[i<<1|1]-l[i<<1|1]+1)*tag[i];
    tag[i]=-1;
}
void change(int x,int y,int val,int i)
{
    if(x<=l[i]&&y>=r[i])
    {
        d[i]=(r[i]-l[i]+1)*val;
        tag[i]=val;
        return;
    }
    pushdown(i);
    int mid=l[i]+r[i]>>1;
    if(y<=mid) change(x,y,val,i<<1);
    else if(x>mid) change(x,y,val,i<<1|1);
    else change(x,y,val,i<<1),change(x,y,val,i<<1|1);
    d[i]=d[i<<1]+d[i<<1|1];
}
int query(int x,int y,int i)
{
    if(x<=l[i]&&y>=r[i]) return d[i];
    pushdown(i);
    int mid=l[i]+r[i]>>1;
    if(y<=mid) return query(x,y,i<<1);
    if(x>mid) return query(x,y,i<<1|1);
    return query(x,y,i<<1)+query(x,y,i<<1|1);
}
inline int check(int x)
{
    Rebuild(1,n,1,x);
    for(re int i=1;i<=m;i++)
    {
        int t=query(X[i],Y[i],1);
        if(!t||t==Y[i]-X[i]+1) continue;
        if(!op[i])
            change(X[i],Y[i]-t,0,1),change(Y[i]-t+1,Y[i],1,1);
        else change(X[i],X[i]+t-1,1,1),change(X[i]+t,Y[i],0,1);
    }
    return query(q,q,1);
}
int main()
{
    n=read();m=read();
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int i=1;i<=m;i++)
        op[i]=read(),X[i]=read(),Y[i]=read();
    build(1,n,1);
    q=read();
    int l=1,r=n,ans;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(!check(mid)) r=mid-1,ans=mid;
        else l=mid+1; 
    }
    std::cout<<ans;
    return 0;
}