zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    今日总结
    今日总结
    今日总结
    今日总结
    今日总结
    java自学
    java自学
    Java自学
    Java自学
    java自学
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/12486900.html
Copyright © 2011-2022 走看看