【bzoj4552】【Tjoi2016】【Heoi2016】【排序】【二分答案】【线段树】

题目大意

给出长度为n的序列,有m个排序操作,对一个区间升序或降序排序,求操作完某一位的值。

题解

一个非常不显然的性质,本题满足二分性质。二分一个答案,如果原数大于或等于答案就标记为1,不然标记为0。排序完可以知道目标位到底是大于等于还是小于答案,适当调整答案即可。

code

#include
#include
#include
#include
#include
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=100000;
int n,m,q,a[maxn+10],l[maxn+10],r[maxn+10],op[maxn+10],ans[maxn*50+10],flag[maxn*50+10];
void change(int now,int l,int r,int l1,int r1,int val){
    if(l1>r1)return;
    int m=(l+r)/2;
    if((flag[now]!=-1)&&(l!=r)){
        ans[now*2]=(m-l+1)*flag[now];
        ans[now*2+1]=(r-m)*flag[now];
        flag[now*2]=flag[now*2+1]=flag[now];
        flag[now]=-1;
    }
    if((l==l1)&&(r==r1)){
        ans[now]=(r-l+1)*val;
        flag[now]=val;
        return;
    }else if(r1<=m)change(now*2,l,m,l1,r1,val);
    else if(m*2+1,m+1,r,l1,r1,val);
    else{
        change(now*2,l,m,l1,m,val);
        change(now*2+1,m+1,r,m+1,r1,val);
    }
    ans[now]=ans[now*2]+ans[now*2+1];
}
int ask(int now,int l,int r,int l1,int r1){
    if(l1>r1)return 0;
    int m=(l+r)/2;
    if((flag[now]!=-1)&&(l!=r)){
        ans[now*2]=(m-l+1)*flag[now];
        ans[now*2+1]=(r-m)*flag[now];
        flag[now*2]=flag[now*2+1]=flag[now];
        flag[now]=-1;
    }
    if((l==l1)&&(r==r1))return ans[now];
    else if(r1<=m)return ask(now*2,l,m,l1,r1);
    else if(mreturn ask(now*2+1,m+1,r,l1,r1);
    else return ask(now*2,l,m,l1,m)+ask(now*2+1,m+1,r,m+1,r1);
}
int main(){
    //freopen("len.in","r",stdin);
    //freopen("len.out","w",stdout);
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n)scanf("%d",&a[i]);
    fo(i,1,m)
        scanf("%d%d%d",&op[i],&l[i],&r[i]);
    scanf("%d",&q);
    int le=1,ri=n;
    memset(flag,255,sizeof(flag));
    while(le!=ri){
        int mid=(le+ri+1)/2;
        fo(i,1,n)
            change(1,1,n,i,i,a[i]>=mid);
        fo(i,1,m){
            int tmp=ask(1,1,n,l[i],r[i]);
            if(op[i]){
                change(1,1,n,l[i],l[i]+tmp-1,1);
                change(1,1,n,l[i]+tmp,r[i],0);
            }else{
                change(1,1,n,l[i],r[i]-tmp,0);
                change(1,1,n,r[i]-tmp+1,r[i],1);
            }
        }
        if(ask(1,1,n,q,q))le=mid;
        else ri=mid-1;
    }
    printf("%d",le);
    return 0;
}

你可能感兴趣的:(bzoj,二分,三分,数据结构)