BZOJ-1828: [Usaco2010 Mar]balloc 农场分配

[文章目录]

Description

给你n段区间,并给你所有位置上最多能被覆盖区间的个数。询问最多能覆盖多少段区间。
n<=10^5 l,r<=10^5 被覆盖个数<=10^5

贪心
对于所有区间按照r由小到大排序,r相同的按照长度由小到大排序,然后顺次判断是否合法,如果合法则选用,线段树维护一下即可。
证明:对于当前区间i,所影响的区间满足lj<=ri,rj>=ri,它们之间互相也影响,不会出现去掉当前可以满足另外两个未选区间的情况。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 101000 
int n,m,ans,mi[N<<2],lz[N<<2];
struct node
{
    int l,r;
}a[N];
bool cmp(node x,node y)
{
    return x.r==y.r ? x.r-x.l < y.r-y.l : x.r<y.r;
}
inline int Min(int x,int y){return x<y ? x:y;}
inline void pushup(int pos)
{
    mi[pos]=Min(mi[pos<<1],mi[pos<<1|1]);
}
inline void pushdown(int pos)
{
    if(lz[pos])
    {
        mi[pos<<1]+=lz[pos];
        mi[pos<<1|1]+=lz[pos];
        lz[pos<<1]+=lz[pos];
        lz[pos<<1|1]+=lz[pos];
        lz[pos]=0;
    }
}
void build(int pos,int l,int r)
{
    if(l==r)
    {
        scanf("%d",mi+pos);
        return ;
    }
    int mid=(l+r)>>1;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    mi[pos]=Min(mi[pos<<1],mi[pos<<1|1]);
}
int query(int pos,int l,int r,int x,int y)
{
    if(x<=l&&y>=r) return mi[pos];
    int mid=(l+r)>>1; pushdown(pos);
    if(y<=mid) return query(pos<<1,l,mid,x,y);
    else if(x>mid) return query(pos<<1|1,mid+1,r,x,y);
    else return Min(query(pos<<1,l,mid,x,y),query(pos<<1|1,mid+1,r,x,y));
}
void fix(int pos,int l,int r,int x,int y)
{
    if(x<=l&&y>=r)
    {
        mi[pos]--; lz[pos]--;
        return ;
    }
    int mid=(l+r)>>1; pushdown(pos);
    if(y<=mid) fix(pos<<1,l,mid,x,y);
    else if(x>mid) fix(pos<<1|1,mid+1,r,x,y);
    else fix(pos<<1,l,mid,x,y),fix(pos<<1|1,mid+1,r,x,y);
    pushup(pos);
}
int main()
{
    scanf("%d%d",&n,&m); build(1,1,n);
    for(int i=1;i<=m;++i) scanf("%d%d",&a[i].l,&a[i].r);
    sort(a+1,a+m+1,cmp); 
    for(int i=1;i<=m;++i)
        if(query(1,1,n,a[i].l,a[i].r))
            ans++,fix(1,1,n,a[i].l,a[i].r);
    printf("%d",ans);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注