HDU-4614 Vases and Flowers(线段树+区间修改+二分)

题目链接

Problem Description
  Alice is so popular that she can receive many flowers everyday. She has N vases numbered from 0 to N-1. When she receive some flowers, she will try to put them in the vases, one flower in one vase. She randomly choose the vase A and try to put a flower in the vase. If the there is no flower in the vase, she will put a flower in it, otherwise she skip this vase. And then she will try put in the vase A+1, A+2, …, N-1, until there is no flower left or she has tried the vase N-1. The left flowers will be discarded. Of course, sometimes she will clean the vases. Because there are too many vases, she randomly choose to clean the vases numbered from A to B(A <= B). The flowers in the cleaned vases will be discarded.

Input
  The first line contains an integer T, indicating the number of test cases.
  For each test case, the first line contains two integers N(1 < N < 50001) and M(1 < M < 50001). N is the number of vases, and M is the operations of Alice. Each of the next M lines contains three integers. The first integer of one line is K(1 or 2). If K is 1, then two integers A and F follow. It means Alice receive F flowers and try to put a flower in the vase A first. If K is 2, then two integers A and B follow. It means the owner would like to clean the vases numbered from A to B(A <= B).

Output
  For each operation of which K is 1, output the position of the vase in which Alice put the first flower and last one, separated by a blank. If she can not put any one, then output ‘Can not put any one.’. For each operation of which K is 2, output the number of discarded flowers.
  Output one blank line after each test case.

Sample Input
2
10 5
1 3 5
2 4 5
1 1 8
2 3 6
1 8 8
10 6
1 2 5
2 3 4
1 0 8
2 2 5
1 4 4
1 2 3

Sample Output
[pre]3 7
2
1 9
4
Can not put any one.

2 6
2
0 9
4
4 5
2 3

[/pre]

题意

有0~n-1 n个花瓶,m次操作,每次操作输入三个数k,x,y。
k为1时,表示需要从第x个花瓶开始,向x+1 x+2…中空花瓶插花,如果有空花瓶的话,输出第一个插花位置与最后一个插花位置,如果没有空花瓶,输出Can not put any one.
k为2时,表示从第x个花瓶开始到第y个花瓶结束,所有花瓶中的花清空,并统计有花的花瓶个数

思路

刚开始很懵逼,完全没有思路,看了大佬的代码思路才知道怎么做。感谢大佬!!!!
由于花瓶序列是0~n-1,所有可以将它向后平移一个单位.将空花瓶定义为1,有花的花瓶定义为0.
清空与插花的操作就不在多说,这里只说一下如何判断第一个与最后一个插花位置。

方法一:

因为我们要确定第一个花瓶的位置,那么我们只需要在一颗树的左子树中查找在x~n的范围内是否有1个空花瓶(因为我们需要的是第一个空花瓶的位置,所有只需要1个空花瓶),如果有那么第一个空花瓶就在这棵树的左子树中,反之则在右子树中,如此下去直至L等于R,便查找到了第一个空花瓶。

现在查找最后一个空花瓶,由于我们不确定x-n中是否足够y个空花瓶,所有需要计算x~n空花瓶数量t,取num=min(t,y)。

同样的道理,我们首先查找一棵树的左子树在x~n的范围内空花瓶数量(ans)是否满足num,若满足则继续查找;若不满足则查找右子树中是否满足num-ans(由于左子树足够ans个空花瓶,那么我还需要从右子树中找num-ans即可)。如此下去,直至L==R,便查找到了最后一个空花瓶。

方法二:
二分答案,同样是查找x~n中空花瓶的数量。
判断第一个空花瓶位置时,判断x~n中左半边是否有1个空花瓶,若有,继续二分,反之判断右半边,直至L等于R。
判断第最后个空花瓶位置时,判断x~n中左半边是否满足num个空花瓶(与方法一中的num相同),若满足继续二分反之判断右半边是否满足(num-ans),直至L==R。

总结与分析:

1.清空花瓶与插花的过程中,忘记回溯修改父亲节点的值。
2.在修改节点值时,必须同时修改tree[rt]与lazy[rt],而不能只修改lazy[rt],在pushdown中修改tree[rt].


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 51000;
int tree[MAXN<<2],lazy[MAXN<<2];

void pushdown(int rt,int L,int R)
{
    lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
    if(lazy[rt]){
        tree[rt<<1]=((L+R)>>1)-L+1;
        tree[rt<<1|1]=R-((L+R)>>1);
    }
    else{
        tree[rt<<1]=0;
        tree[rt<<1|1]=0;
    }
    lazy[rt]=-1;
    return ;
}

void build(int rt,int L,int R)
{
    lazy[rt]=-1;
    if(L==R){
        tree[rt]=1;
        return ;
    }
    int Mid = (L+R)>>1;
    build(rt<<1,L,Mid);
    build(rt<<1|1,Mid+1,R);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}

void update(int rt,int L,int R,int l,int r)
{
    if(l<=L&&R<=r){
        tree[rt]=0;
        lazy[rt]=0;
        return ;
    }
    int Mid = (L+R)>>1;
    if(lazy[rt]!=-1)    pushdown(rt,L,R);
    if(l<=Mid)  update(rt<<1,L,Mid,l,r);
    if(Mid<r)   update(rt<<1|1,Mid+1,R,l,r);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}

int query(int rt,int L,int R,int l,int r)
{
    if(l>R||r<L)    return 0;
    if(l<=L&&R<=r)
        return tree[rt];
    if(lazy[rt]!=-1)    pushdown(rt,L,R);
    int Mid = (L+R)>>1;
    int ans=0;
    if(l<=Mid)
        ans+=query(rt<<1,L,Mid,l,r);
    if(Mid<r)
        ans+=query(rt<<1|1,Mid+1,R,l,r);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
    return ans;
}

void Clear(int rt,int L,int R,int l,int r)
{
    if(l<=L&&R<=r){
        tree[rt]=R-L+1;
        lazy[rt]=1;
        return ;
    }
    if(lazy[rt]!=-1)    pushdown(rt,L,R);
    int Mid = (L+R)>>1;
    if(l<=Mid)  Clear(rt<<1,L,Mid,l,r);
    if(Mid<r)   Clear(rt<<1|1,Mid+1,R,l,r);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}

int ask(int rt,int L,int R,int l,int r,int num)
{
    if(L==R)
        return L;
    if(lazy[rt]!=-1)    pushdown(rt,L,R);
    int Mid = (L+R)>>1;
    int t = query(rt<<1,L,Mid,l,r);
    if(num<=t)  return ask(rt<<1,L,Mid,l,r,num);
    return ask(rt<<1|1,Mid+1,R,l,r,num-t);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        build(1,1,n);
        while(m--){
            int k,x,y;
            cin>>k>>x>>y;
            if(k==1){
                x++;
                int t=query(1,1,n,x,n);
                if(t==0)
                    printf("Can not put any one.\n");
                else{
                    int l=ask(1,1,n,x,n,1);
                    int r=ask(1,1,n,x,n,min(t,y));
                    printf("%d %d\n",l-1,r-1);
                    update(1,1,n,l,r);
                }
            }
            else{
                x++;y++;
                printf("%d\n",y-x+1-query(1,1,n,x,y));
                Clear(1,1,n,x,y);
            }
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值