bzoj4552: [Tjoi2016&Heoi2016]排序(二分+线段树)

Posted Sakits

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4552: [Tjoi2016&Heoi2016]排序(二分+线段树)相关的知识,希望对你有一定的参考价值。

  又是久违的1A哇...

  好喵喵的题!二分a[p],把大于mid的数改为1,小于等于mid的数改为0,变成01串后就可以用线段树进行那一连串排序了,排序后如果p的位置上的数为0,说明答案比mid小,如果为1,说明答案比mid大。

  如何理解呢?我们的目的其实是让比a[p]大的数都为1,这样子p位置上刚好为0。如果p位置上为1,说明mid较小,a[p]>mid,把a[p]给标记成了1。如果p位置上为0,就是把a[p]<=mid,把a[p]标记成了0,但是这样还有一些大于a[p]的位置也是0,所以继续往小的地方逼近答案。

技术分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
using namespace std;
const int maxn=500010,inf=1e9;
struct poi{int sum,tag;}tree[maxn];
int n,m,q;
int a[maxn],b[maxn],l[maxn],r[maxn],ty[maxn];
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
inline void pushup(int x){tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;}
inline void pushdown(int x,int l,int r)
{
    if(tree[x].tag==-1)return;
    int mid=(l+r)>>1;
    if(tree[x].tag==1)
    {
        tree[x<<1].sum=mid-l+1;tree[x<<1].tag=1;
        tree[x<<1|1].sum=r-mid;tree[x<<1|1].tag=1;
    } 
    else tree[x<<1].sum=tree[x<<1|1].sum=tree[x<<1].tag=tree[x<<1|1].tag=0;
    tree[x].tag=-1;
}
void build(int x,int l,int r)
{
    tree[x].tag=-1;
    if(l==r){tree[x].sum=b[l];return;}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    pushup(x);
}
void update(int x,int l,int r,int cl,int cr,int ty)
{
    if(cl<=l&&r<=cr){tree[x].sum=ty*(r-l+1);tree[x].tag=ty;return;}
    pushdown(x,l,r);
    int mid=(l+r)>>1;
    if(cl<=mid)update(x<<1,l,mid,cl,cr,ty);
    if(cr>mid)update(x<<1|1,mid+1,r,cl,cr,ty);
    pushup(x);
} 
int query(int x,int l,int r,int cl,int cr)
{
    if(cl<=l&&r<=cr)return tree[x].sum;
    pushdown(x,l,r);
    int mid=(l+r)>>1,ret=0;
    if(cl<=mid)ret+=query(x<<1,l,mid,cl,cr);
    if(cr>mid)ret+=query(x<<1|1,mid+1,r,cl,cr);
    return ret;
} 
bool check(int x)
{
    for(int i=1;i<=n;i++)b[i]=a[i]>x;
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int x=query(1,1,n,l[i],r[i]);
        if(ty[i])
        {
            if(x)update(1,1,n,l[i],l[i]+x-1,1);
            if(l[i]+x<=r[i])update(1,1,n,l[i]+x,r[i],0);
        }
        else
        {
            if(l[i]<=r[i]-x)update(1,1,n,l[i],r[i]-x,0);
            if(x)update(1,1,n,r[i]-x+1,r[i],1);
        } 
    }
    return !query(1,1,n,q,q);
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)read(a[i]);
    for(int i=1;i<=m;i++)read(ty[i]),read(l[i]),read(r[i]);
    read(q);
    int l=1,r=n;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    printf("%d",l); 
}
View Code

 

以上是关于bzoj4552: [Tjoi2016&Heoi2016]排序(二分+线段树)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 4552: [Tjoi2016&Heoi2016]排序

[BZOJ4552][TJOI2016&&HEOI2016]排序

BZOJ4552:[Tjoi2016&Heoi2016]排序

[BZOJ] 4552: [Tjoi2016&Heoi2016]排序 #二分+线段树+算法设计策略

bzoj 4552 [Tjoi2016&Heoi2016]排序——二分答案

bzoj千题计划128:bzoj4552: [Tjoi2016&Heoi2016]排序