Vases and Flowers HDU

题意:

给出 (n) 个花瓶,编号 ([0,n-1]),一开始每个花瓶是空的。输入 (K)(Alice) 有两种操作,共 (m) 个:
(K=1):输入 (A,F)(Alice) 将从花瓶 (A) 开始,向空花瓶中插入花,如果没有插完,则多余的花舍弃;
(K=2):输入 (A,B)(Alice) 建将把花瓶 (A,B) 之间的花清除掉,求出清除的花的数量,(Aleq 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) 标记,不能累加,直接修改即可。
区间修改时,如果区间满足 (Lleq 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.
");
                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
",star-1,en-1);
                }
            }
            else
            {
                printf("%d
",c-b+1-query1(1,n,b+1,c+1,1));
                update(1,n,b+1,c+1,1,1);//清空花瓶->1
            }
        }
        printf("
");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/1024-xzx/p/12486900.html