HDU 4614 Vases and Flowers(线段树)

题目链接

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

3 7
2
1 9
4
Can not put any one.

2 6
2
0 9
4
4 5
2 3

题意:现在有n个花瓶,编号0-n-1,每支花瓶只能装一枝花。期初花瓶都是空的,现在有两个操作,操作1:给出一起起点,和n朵花,要求你从起点花瓶开始,遇到没有放花的花瓶就放一枝花,要是花瓶用完了,剩下没放完的花就不要了,要是一朵花都放不了就输出给定字符串,否则输出能插花的区间。操作2:给出一个l,r。要求把这个区间花瓶里的花全部拔掉,并且输出被拔掉的花的数目。

题解:首先这个题,要区间查询和区间修改,应该能想到是线段树,但是怎么维护往里面放花就很难。首先声明一个数组。

用1来表示该位是空着,0表示该位已经插了花,在初始化一个懒标记数组都为-1,表示不用下放,要是该位是0或1都要下放数组。

操作2:很简单就是先计算[l,r]区间里有多少空的(1的个数),再用区间长度减去1的个数就是拔掉花的数目,记得跟新区间。

操作1,:现假定 给定位置为pos,需要插花的数目为s。相对来说操作1就比较麻烦了,首先我们应该计算pos到n-1没有插花的花瓶数目(区间1的数目),要是这个数目为sum1,说明一朵花也插不进去,直接输出给定字符串。要是sum不为0,我们就要计算右端点在哪了,现在我们计算0-n-1总共有sum2花瓶是空的.我们用temp=sum2-sum1就表示在pos这个点前面总共有这么多花瓶是空的。所以我们计算1的个数[temp,temp+min(s,sum)](应该后面最多还有sum个空瓶,所以这里要取两个中的较小值)。现在我们就直接找,因为,sum数组保存的区间1的个数,所以我们直接找[0,l]区间1个个数为temp+1的l的位置,同理找r的位置,这两个就是我们插花的区间,最后记得将区间值都赋值为0。

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=5e4+5;
const int mod=20190414;
const int inf=1e9;
const long long onf=1e18;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI 3.14159265358979323846
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int sum[maxn<<2],lazy[maxn<<2];
///sum数组1表示该花瓶是空的,0表示该花瓶是有花的
void push_up(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void push_down(int l,int r,int rt){
    if(lazy[rt]!=-1){///要是lazy数组值不为-1则说明需要下放
        int mid=(l+r)>>1;
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        sum[rt<<1]=(mid-l+1)*lazy[rt];
        sum[rt<<1|1]=(r-mid)*lazy[rt];
        lazy[rt]=-1;
    }
}
void build(int l,int r,int rt){///建树
    lazy[rt]=-1;
    sum[rt]=r-l+1;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}
void push_date(int L,int R,int x,int l,int r,int rt){//更新
    if(L<=l&&R>=r){
        sum[rt]=(r-l+1)*x;
        lazy[rt]=x;
        return ;
    }
    push_down(l,r,rt);
    int mid=(l+r)>>1;
    if(L<=mid)
        push_date(L,R,x,lson);
    if(R>mid)
        push_date(L,R,x,rson);
    push_up(rt);
}
int query(int L,int R,int l,int r,int rt){///计算去1的个数
    if(L<=l&&R>=r)
        return sum[rt];
    push_down(l,r,rt);
    int mid=(l+r)>>1;
    int ans=0;
    if(L<=mid)
        ans+=query(L,R,lson);
    if(R>mid)
        ans+=query(L,R,rson);
    return ans;
}
void look_pos(int s,int &pos,int l,int r,int rt){///找区间端点
    if(l==r){
        pos=l;
        return ;
    }
    push_down(l,r,rt);
    int mid=(l+r)>>1;
    if(sum[rt<<1]>=s)///要是左子树的1的个数大于s,,说明端点在左子树里
        look_pos(s,pos,lson);
    else
        look_pos(s-sum[rt<<1],pos,rson);///端点在右子树,因为我们保存的是区间1的个数,所以要减去整个左区间1的个数。
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        build(0,n-1,1);
        while(m--){
            int k;
            scanf("%d",&k);
            if(k==1){
                int pos,s;
                scanf("%d%d",&pos,&s);
                int sum=query(pos,n-1,0,n-1,1);///计算[pos,n-1]中1的个数
                if(sum==0)///一枝花也插不了
                    printf("Can not put any one.\n");
                else{
                    int sam=query(0,n-1,0,n-1,1);///计算整个区间中1的个数
                    int temp=sam-sum;///计算pos前面的有多少花瓶是空的
                    int l,r;
                    look_pos(temp+1,l,0,n-1,1);///找l位置
                    look_pos(temp+min(sum,s),r,0,n-1,1);///找r位置
                    push_date(l,r,0,0,n-1,1);///更新
                    printf("%d %d\n",l,r);
                }
            }else{
                int l,r;
                scanf("%d%d",&l,&r);
                int sum=query(l,r,0,n-1,1);///区间中没有插花的花瓶数目
                push_date(l,r,1,0,n-1,1);
                printf("%d\n",r-l+1-sum);
            }
        }
        printf("\n");
    }
    return 0;
}

二分找[l,r];

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=5e4+5;
const int mod=20190414;
const int inf=1e9;
const long long onf=1e18;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI 3.14159265358979323846
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int sum[maxn<<2],lazy[maxn<<2];
///sum数组1表示该花瓶是空的,0表示该花瓶是有花的
int n,m;
void push_up(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void push_down(int l,int r,int rt){
    if(lazy[rt]!=-1){///要是lazy数组值不为-1则说明需要下放
        int mid=(l+r)>>1;
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        sum[rt<<1]=(mid-l+1)*lazy[rt];
        sum[rt<<1|1]=(r-mid)*lazy[rt];
        lazy[rt]=-1;
    }
}
void build(int l,int r,int rt){///建树
    lazy[rt]=-1;
    sum[rt]=r-l+1;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}
void push_date(int L,int R,int x,int l,int r,int rt){//更新
    if(L<=l&&R>=r){
        sum[rt]=(r-l+1)*x;
        lazy[rt]=x;
        return ;
    }
    push_down(l,r,rt);
    int mid=(l+r)>>1;
    if(L<=mid)
        push_date(L,R,x,lson);
    if(R>mid)
        push_date(L,R,x,rson);
    push_up(rt);
}
int query(int L,int R,int l,int r,int rt){///计算去1的个数
    if(L<=l&&R>=r)
        return sum[rt];
    push_down(l,r,rt);
    int mid=(l+r)>>1;
    int ans=0;
    if(L<=mid)
        ans+=query(L,R,lson);
    if(R>mid)
        ans+=query(L,R,rson);
    return ans;
}
int look_pos(int l,int r,int val){///找区间端点
    int x=l,ans;
    while(l<=r){
        int mid=(l+r)>>1;
        if(query(x,mid,0,n-1,1)>=val){
            ans=mid;
            r=mid-1;
        }else
            l=mid+1;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        build(0,n-1,1);
        while(m--){
            int k;
            scanf("%d",&k);
            if(k==1){
                int pos,s;
                scanf("%d%d",&pos,&s);
                int sum=query(pos,n-1,0,n-1,1);///计算[pos,n-1]中1的个数
                if(sum==0)///一枝花也插不了
                    printf("Can not put any one.\n");
                else{
                    int l=look_pos(pos,n-1,1);///在pos后找插第一只花的位置为l
                    int r=look_pos(pos,n-1,min(sum,s));///找r位置
                    push_date(l,r,0,0,n-1,1);///更新
                    printf("%d %d\n",l,r);
                }
            }else{
                int l,r;
                scanf("%d%d",&l,&r);
                int sum=query(l,r,0,n-1,1);///区间中没有插花的花瓶数目
                push_date(l,r,1,0,n-1,1);
                printf("%d\n",r-l+1-sum);
            }
        }
        printf("\n");
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值