Vases and Flowers HDU - 4614【线段树+主席树思维/二分】

题意:

给出 \(n\) 个花瓶,编号 \([0,n-1]\),一开始每个花瓶是空的。输入 \(K\)\(Alice\) 有两种操作,共 \(m\) 个:
\(K=1\):输入 \(A,F\)\(Alice\) 将从花瓶 \(A\) 开始,向空花瓶中插入花,如果没有插完,则多余的花舍弃;
\(K=2\):输入 \(A,B\)\(Alice\) 建将把花瓶 \(A,B\) 之间的花清除掉,求出清除的花的数量,\(A\leq B\)
数据范围: \(1 < N,M < 50001\)

分析1:

  主席树求区间第 \(k\) 大的思想。以 \(1\) 表示花瓶为空,\(0\) 表示花瓶有花,把区间变成 \([1,n]\),输入位置相应 \(+1\)。当进行插花操作时,我们先求出 \([A,N]\) 区间内的空花瓶数目,假设为 \(t\)。如果 \(t=0\),表示无法插入花;否则,我们寻找到进行插花的花瓶的左右区间端点,然后利用简单的区间修改即可完成插花操作。如何找到端点呢?我们先求出区间 \([1,A-1]\) 内的空花瓶数,假设为 \(p\),那么只要找到整个区间的第 \(p+1\) 和第 \(p+min(F,t)\) 个空花瓶即可。这些操作,可以类比于主席树区间求第 \(k\) 大。

代码实现:
  注意 \(lazy\) 标记,不能累加,直接修改即可。
区间修改时,如果区间满足 \(L\leq l\;\&\&\;r \leq R\) ,可以直接赋值。不用考虑区间内是否是空花瓶和有花花瓶共存的情况,\(lazy\) 标记下放时,也是如此。一开始把把这些区间区分开,写起来很麻烦,也任意错。具体见代码。

代码1:

#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5;
int tree[N<<2],lazy[N<<2];
void build(int l,int r,int rt)
{
    lazy[rt]=-1;
    if(l==r)
    {
        tree[rt]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void pushdown(int ln,int rn,int rt)
{
    if(lazy[rt]!=-1)
    {
        lazy[rt<<1]=lazy[rt];
        lazy[rt<<1|1]=lazy[rt];
        if(lazy[rt]==1)
        {
            tree[rt<<1]=ln;
            tree[rt<<1|1]=rn;
        }
        else
        {
            tree[rt<<1]=0;
            tree[rt<<1|1]=0;
        }
        lazy[rt]=-1;
    }
}
void update(int l,int r,int L,int R,int val,int rt)
{
    if(L<=l&&r<=R)//注意
    {
        tree[rt]=val*(r-l+1);
        lazy[rt]=val;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(mid-l+1,r-mid,rt);
    if(L<=mid)
        update(l,mid,L,R,val,rt<<1);
    if(R>mid)
        update(mid+1,r,L,R,val,rt<<1|1);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
int query1(int l,int r,int L,int R,int rt)//简单区间求和
{
    if(L<=l&&r<=R)
        return tree[rt];
    int mid=(l+r)>>1,ans=0;
    pushdown(mid-l+1,r-mid,rt);
    if(L<=mid)
        ans+=query1(l,mid,L,R,rt<<1);
    if(R>mid)
        ans+=query1(mid+1,r,L,R,rt<<1|1);
    return ans;
}
int query2(int l,int r,int L,int R,int k,int rt)//求区间第k个空花瓶
{
    if(l==r)
        return l;
    int mid=(l+r)>>1;
    pushdown(mid-l+1,r-mid,rt);
    if(tree[rt<<1]>=k)
        return query2(l,mid,L,R,k,rt<<1);
    else
        return query2(mid+1,r,L,R,k-tree[rt<<1],rt<<1|1);
}
int main()
{
    int t,n,m,a,b,c,cot=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        build(1,n,1);
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(a==1)
            {
                int t=query1(1,n,b+1,n,1);//区间求和,看是否有空花瓶
                if(t==0)
                    printf("Can not put any one.\n");
                else
                {
                    int p=(b>0?query1(1,n,1,b,1):0);//[1,b]内的花瓶数量
                    int star=query2(1,n,1,n,p+1,1);
                    int en=query2(1,n,1,n,p+min(t,c),1);
                    update(1,n,star,en,0,1);//插花->0
                    printf("%d %d\n",star-1,en-1);
                }
            }
            else
            {
                printf("%d\n",c-b+1-query1(1,n,b+1,c+1,1));
                update(1,n,b+1,c+1,1,1);//清空花瓶->1
            }
        }
        printf("\n");
    }
    return 0;
}

posted @ 2020-03-13 15:40  xzx9  阅读(112)  评论(0编辑  收藏  举报