Vases and Flowers HDU

来源:互联网 发布:excel怎么剔除重复数据 编辑:程序博客网 时间:2024/05/20 06:08
   Alice有N个花瓶(标号为0~ N-1)。当她收到一些花时,她会随机的选择一个瓶子A,从它开始遍历A,A+1, A+2, ..., N-1号瓶子,遇到空瓶子就放一朵花进去,直到花朵放完或没有瓶子,剩下的花将被丢弃。有时,她也会清理标号从A到B的花瓶(A <= B).花瓶里的花会被丢弃。

Input

  第一行一个整数T,表示数据组数。
  每组数据,第一行一个整数N(1 < N < 50001) and M(1 < M < 50001). N 是花瓶个数,  M是Alice的操作次数. 接下来M行 行3个 整数. 第一个整数 K(1 or 2). 如果K=1, 后面跟两个整数 A 和  F . 表示Alice得到了F 朵花并且把它们放入从A 的花瓶里. 如果K= 2,后跟两个整数 A 和  B. 表示Alice  清理的花瓶标号范围(A <= B).

Output

  对于每个K=1的操作,输出第一朵和最后一朵花放置的花瓶标号。如果没有任何放花的位置,输出'Can not put any one.'.对于K=2的操作,输出丢弃花的个数.
   每组数据后输出一个空行.

Sample Input
210 51 3 52 4 51 1 82 3 61 8 810 61 2 52 3 41 0 82 2 51 4 41 2 3
Sample Output
3 721 94Can not put any one.2 620 944 52 3刚拿到这道题又是很懵。然后仔细想了一下,发现不是很难。当2操作的时候,要显示更改的次数,说明线段树肯定是要存储区间和的。存储什么和呢?
仔细想一下你会发现,还是储存没有被占用的点的个数合适。这样就可以求出区间的操作1的l和r。因为你知道任何一个区间的未占用的个数
那么就可以用二分来求出第一个未占用的点在哪里,同理,可以求出最后一个点在哪里。再用线段树更新更新l,r。这里最大的难度可能就是二分查找了,还好昨天做过cf,
里面有类似这样的查找机制,直接套用了。

下面给出代码

#include<bits/stdc++.h>using namespace std;const int M=5e4+10;int lazy[4*M],tree[4*M],n;void creat(int now,int l,int r){    lazy[now]=-1;    if(l==r)    {        tree[now]=1;//叶子节点一个0        return ;    }    int mid=(l+r)/2;    creat(now*2+1,l,mid);    creat(now*2+2,mid+1,r);    tree[now]=tree[now*2+1]+tree[now*2+2];}void pushdown(int now,int l,int r){    if(lazy[now]!=-1)    {        int mid=(l+r)/2;        lazy[now*2+1]=lazy[now*2+2]=lazy[now];        lazy[now]=-1;        tree[now*2+1]=lazy[now*2+1]*(mid-l+1);        tree[now*2+2]=lazy[now*2+2]*(r-mid);    }}int query(int now,int l,int r,int al,int ar){    int mid=(l+r)/2;    if(al>r||ar<l)        return 0;    if(al<=l&&ar>=r)        return tree[now];    pushdown(now,l,r);    return query(now*2+1,l,mid,al,ar)+query(now*2+2,mid+1,r,al,ar);}void update(int now,int l,int r,int al,int ar,int val){    int mid=(l+r)/2;    if(al>r||ar<l)        return ;    if(al<=l&&ar>=r)    {        lazy[now]=val;        tree[now]=val*(r-l+1);        return ;    }    pushdown(now,l,r);    update(now*2+1,l,mid,al,ar,val);    update(now*2+2,mid+1,r,al,ar,val);    tree[now]=tree[now*2+1]+tree[now*2+2];}int find1(int l,int r){    int ans;    while(l<=r)    {        int mid=(l+r)/2;        int sum=query(0,0,n-1,l,mid);        if(sum>0)//存在没有插的位置        {            ans=mid;            r=mid-1;        }        else        {            l=mid+1;        }    }    return ans;}int find2(int l,int r,int remind){    int ans;    int k=l;    while(l<=r)    {        int mid=(l+r)/2;        int sum=query(0,0,n-1,k,mid);        if(sum>=remind)        {            ans=mid;            r=mid-1;        }        else        {            l=mid+1;        }    }    return ans;}int main(){    int t,m;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        creat(0,0,n-1);        while(m--)        {            int op,a,b;            scanf("%d%d%d",&op,&a,&b);            if(op==1)            {                int have=query(0,0,n-1,a,n-1);                if(!have)                {                    printf("Can not put any one.\n");                    continue;                }                int left=find1(a,n-1);                int right=find2(a,n-1,min(have,b));                update(0,0,n-1,left,right,0);                printf("%d %d\n",left,right);            }            else            {                int have1=query(0,0,n-1,a,b);                update(0,0,n-1,a,b,1);                int have2=query(0,0,n-1,a,b);                printf("%d\n",have2-have1);            }        }        putchar('\n');    }}




原创粉丝点击