BZOJ 4552: [Tjoi2016&Heoi2016]排序

二分套线段树

因为最后只要求一个位置上的数是多少,所以二分一下就好了,二分这个位置上的数的大小。
如何判定呢?
把每一个大于等于这个数的数都赋值为1,小于这个数的数赋值为0,然后对于升序降序操作,就是把区间内的0或1放置到区间前端或区间后端即可。
修改完成后,判断那个位置的数值是0还是1即可,如果是1即说明符合了。如果是0即不符。
稍微想一下可以大致理解这是有单调性的。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,p,l,r,ans;
int a[N],sum[N<<2],tag[N<<2];
struct number{int opt,l,r;}num[N];
 
void build(int k,int l,int r,int v)
{
    if (l==r)
    {
        sum[k]=(a[l]>=v);
        tag[k]=-1;
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid,v);
    build(k<<1|1,mid+1,r,v);
    sum[k]=sum[k<<1]+sum[k<<1|1];
    tag[k]=-1;
}
 
inline void pushdown(int k,int l,int r)
{
    if (tag[k]==-1) return;
    tag[k<<1]=tag[k<<1|1]=tag[k];
    int mid=l+r>>1;
    sum[k<<1]=(mid-l+1)*tag[k];
    sum[k<<1|1]=(r-(mid+1)+1)*tag[k];
    tag[k]=-1;
}
 
void change(int k,int l,int r,int qx,int qy,int v)
{
    if (qx>qy) return;
    if (qx<=l && r<=qy)
    {
        sum[k]=(r-l+1)*v;
        tag[k]=v;
        return;
    }
    pushdown(k,l,r);
    int mid=l+r>>1;
    if (qx<=mid) change(k<<1,l,mid,qx,qy,v);
    if (mid<qy) change(k<<1|1,mid+1,r,qx,qy,v);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
 
int query(int k,int l,int r,int qx,int qy)
{
    if (qx<=l && r<=qy) return sum[k];
    pushdown(k,l,r);
    int ans=0;
    int mid=l+r>>1;
    if (qx<=mid) ans+=query(k<<1,l,mid,qx,qy);
    if (mid<qy) ans+=query(k<<1|1,mid+1,r,qx,qy);
    return ans;
}
 
int query2(int k,int l,int r,int pos)
{
    if (l==pos && pos==r) return sum[k];
    pushdown(k,l,r);
    int mid=l+r>>1;
    if (pos<=mid) return query2(k<<1,l,mid,pos);
    else return query2(k<<1|1,mid+1,r,pos);
}
 
inline bool jay(int mid)
{
    build(1,1,n,mid);
    for (register int i=1; i<=m; ++i)
    {
        int cnt=query(1,1,n,num[i].l,num[i].r);
        if (!num[i].opt)
        {
            change(1,1,n,num[i].r-cnt+1,num[i].r,1);
            change(1,1,n,num[i].l,num[i].r-cnt,0);
        }
        else
        {
            change(1,1,n,num[i].l,num[i].l+cnt-1,1);
            change(1,1,n,num[i].l+cnt,num[i].r,0);
        }
    }
    if (query2(1,1,n,p)) return true;
    else return false;
}
 
int main(){
    scanf("%d%d",&n,&m);
    for (register int i=1; i<=n; ++i) scanf("%d",&a[i]);
    for (register int i=1; i<=m; ++i) scanf("%d%d%d",&num[i].opt,&num[i].l,&num[i].r);
    scanf("%d",&p);
    l=1; r=n;
    while (l<=r)
    {
        int mid=l+r>>1;
        if (jay(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
return 0;   
}
发布了64 篇原创文章 · 获赞 29 · 访问量 665

猜你喜欢

转载自blog.csdn.net/Dove_xyh/article/details/104057342