HDU 4614 Vases and Flowers

  Vases and Flowers

 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
 Total Submission(s): 4506    Accepted Submission(s): 1851


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]
 

 

Author
SYSU
 

 

Source
 
思路:
 

这题是线段树

首先这是区间查询,但是在节点上,不容易直接存下要查询的信息,因为这个玩意并不是直接问的固定区间,所以,我们需要另寻它路。

在节点上,我们就存下在这个区间上,一共插了多少花,因为每个花瓶只能插一朵花,所以根据区间长度,也很容易算出还有多少花瓶没有插花。我们在做询问时,询问的是,要插画的具体开始位置,和要插花的具体数量,所以我们采用以下步骤解决问题。

1.询问出从开始点到区间终止点的花朵数量,如果这个数量等于区间的长度,那么就是一朵都插不了了。否则,拿区间长度减去这个数量,就是可以插得数量。如果可以插的数量大于等于要插的花,那么便可以全部插完,否则,就要修改要插的数量,毕竟多了也没用,而且修改后,方便了接下来的二分搜索。

2.二分查找:左端点初始化为起始点,右端点初始化为区间结束点。mid查询从起始点到mid可以插的花数量。查询花朵要开始插的点时,设定二分的判定标准为1,就是只差插一朵花,查询插入的最后一个点时,就是要将判断标准弄成要插的总数。

3.修改,将插入的第一个点和最后的一个点之间全部弄成已经插花的状态。

这样我们就完成了一次查询,要清空的应该就比较简单了。

没想到一发A了,对我来说太不容易了!!!

注意题目里面那些乱七八糟的【pre】不要输出,忽视他们就好了

代码

#include<iostream>
using namespace std;
int n,m;
struct node
{
    int l,r,num,lazy;
}tree[50005<<2];
int d,x,y;


void build(int t,int l,int r)
{
//    cout<<t<<" "<<l<<" "<<r<<endl;
    tree[t].l=l;
    tree[t].r=r;
    tree[t].num=0;
    tree[t].lazy=0;
    if(l==r){return ;}
    int mid=(l+r)>>1;
    build(t<<1,l,mid);
    build((t<<1)|1,mid+1,r);
}

void push_down(int t)
{
    tree[t<<1].num=(tree[t<<1].r-tree[t<<1].l+1)*max(0,tree[t].lazy);
    tree[(t<<1)|1].num=(tree[(t<<1)|1].r-tree[(t<<1)|1].l+1)*max(0,tree[t].lazy);
    if(tree[t<<1].r!=tree[t<<1].l){tree[t<<1].lazy=tree[t].lazy;}
    if(tree[(t<<1)|1].r!=tree[(t<<1)|1].l){tree[(t<<1)|1].lazy=tree[t].lazy;}
    tree[t].lazy=0;
}

void update(int t,int l,int r,int num)
{

//    cout<<t<<" "<<tree[t].l<<" "<<tree[t].r<<" "<<l<<" "<<r<<endl;
    if(tree[t].l==l&&tree[t].r==r){
        tree[t].num=(r-l+1)*num;
        if(l!=r){
            if(num==1)tree[t].lazy=1;
            else tree[t].lazy=-1;
        }

        return;
    }
    if(tree[t].lazy){push_down(t);}
    int mid=(tree[t].l+tree[t].r)>>1;
    if(r<=mid){update(t<<1,l,r,num);}
    else if(l>mid){update((t<<1)|1,l,r,num);}
    else {
        update(t<<1,l,mid,num);
        update((t<<1)|1,mid+1,r,num);
    }
    tree[t].num=tree[t<<1].num+tree[(t<<1)|1].num;
}

int query(int t,int l,int r)
{

//    cout<<t<<" "<<l<<" "<<r<<" "<<tree[t].l<<" "<<tree[t].r<<endl;
    if(tree[t].l==l&&tree[t].r==r){
        return tree[t].num;
    }
    if(tree[t].lazy){push_down(t);}
    int ans=0;
    int mid=(tree[t].l+tree[t].r)>>1;
    if(r<=mid){
        return query(t<<1,l,r);
    }
    else if(l>mid){
        return query((t<<1)|1,l,r);
    }
    else{
        ans+= query(t<<1,l,mid);
        ans+= query((t<<1)|1,mid+1,r);
    }
    return ans;
}


int dive(int s,int num)
{
    int sum=query(1,s,n);
    if(n-s+1==sum){//sum是已经插了的花数目
        return -1;
    }
    else{
        num=min(n-s+1-sum,num);
    }
    int l=s,r=n;
    int mid,ans=s;

    while(r>=l){
        mid=(l+r)>>1;
        sum=mid-s+1-query(1,s,mid);
//        cout<<l<<"LLL"<<r<<endl;
//        cout<<s<<" "<<mid<<" "<<sum<<endl;
        if(sum<num){
            l=mid+1;
        }
        else if(sum>num){
            r=mid-1;
        }
        else{
            ans=mid;
            r=mid-1;
        }
    }
    return ans;
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        n--;
        build(1,0,n);

//        for(int i=1;i<=n*4;i++){
//            printf("%d: %d %d\n",i,tree[i].l,tree[i].r);
//        }

        int start,endd;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&d,&x,&y);
            if(d==1){
                start=dive(x,1);
                endd=dive(x,y);
                if(endd==-1){printf("Can not put any one.\n");continue;}
                else printf("%d %d\n",start,endd);
                update(1,start,endd,1);
            }
            else if(d==2){
                printf("%d\n",query(1,x,y));
                update(1,x,y,0);
            }
        }
        printf("\n");
    }
}

  

posted @ 2018-07-26 10:42  断腿三郎  阅读(192)  评论(0编辑  收藏  举报