hdu4614

 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

现在要你插花,有n个花瓶,m次操作,初始花瓶中无花,操作有两种方式

操作1:1 a b,从编号为a的花瓶开始插花,共插b朵花,花只能插到无花的花瓶中,如果最后插不完b朵花,剩下的花舍弃掉 
操作2:1 a b,把从编号a到编号b的所有花瓶里的花全部清理掉

对于操作1,需要输出开始插花的瓶子编号,和最后插花的瓶子编号 
对于操作2,需要输出在a~b中总共清理了多少个花瓶中的花

题解:线段树+二分,分析一下这道题,如果是情理,那是十分容易的,只需要lazy,tag就可以了,但是如何去找区间第一个可以插的位置呢,

   线段树可以记录该位置里的有多少个空位置,那么我们可以二分,来查找判断是多了,还是少了,这样就可以了,时间复杂度就控制了

   下来,然后整个区间填满,什么区间?就是第一支花和最后一枝花那个区间,hh。

  1 #include<iostream>
  2 #include<stdio.h>
  3 #include<map>
  4 #include<algorithm>
  5 #include<math.h>
  6 #include<queue>
  7 #include<stack>
  8 #include<string>
  9 #include<cstring>
 10 using namespace std;
 11 struct node
 12 {
 13     int l,r;
 14     int tag;//如果为-1则为初始状态,如果为0意思将子区间内的花清空,为1为插满花
 15     int v;//记录区间内插了多少花
 16 }t[50005*4];
 17 int n;
 18 void Build(int l,int r,int k)
 19 {
 20     t[k].l=l;
 21     t[k].r=r;
 22     t[k].v=0;
 23     t[k].tag=-1;
 24     if(l==r)
 25         return;
 26     int mid=(l+r)/2;
 27     Build(l,mid,k*2);
 28     Build(mid+1,r,k*2+1);
 29 }
 30 void pushdown(int k)//向下传递状态
 31 {
 32     t[k*2].tag=t[k*2+1].tag=t[k].tag;
 33     t[k*2].v=t[k].tag*(t[k*2].r-t[k*2].l+1);
 34     t[k*2+1].v=t[k].tag*(t[k*2+1].r-t[k*2+1].l+1);
 35     t[k].tag=-1;
 36 }
 37 void update(int l,int r,int v,int k)
 38 {
 39     if(t[k].l==l&&t[k].r==r)
 40     {
 41         t[k].tag=v;
 42         t[k].v=v*(r-l+1);//插满或者清空
 43         return;
 44     }
 45     if(t[k].tag!=-1)//要传递状态
 46         pushdown(k);
 47     int mid=(t[k].l+t[k].r)/2;
 48     if(r<=mid)
 49         update(l,r,v,k*2);
 50     else if(l>mid)
 51         update(l,r,v,k*2+1);
 52     else
 53     {
 54         update(l,mid,v,k*2);
 55         update(mid+1,r,v,k*2+1);
 56     }
 57     t[k].v=t[k*2].v+t[k*2+1].v;//向上传递区间信息
 58 }
 59 int query(int l,int r,int k)//查询区间内插花的数目
 60 {
 61     if(t[k].l==l&&t[k].r==r)
 62     {
 63         return t[k].v;
 64     }
 65     if(t[k].tag!=-1)//同样lazy tag
 66         pushdown(k);
 67     int mid=(t[k].l+t[k].r)/2;
 68     if(r<=mid)
 69         return query(l,r,k*2);
 70     else if(l>mid)
 71         return query(l,r,k*2+1);
 72     else
 73     {
 74         return query(l,mid,k*2)+query(mid+1,r,k*2+1);
 75     }
 76     t[k].v=t[k*2].v+t[k*2+1].v;
 77 }
 78 int dive(int s,int num)//二分查找,第一个为开始的位置,第二个参数为要插多少个
 79 {
 80     int temp=query(s,n,1);
 81     if(temp==n-s+1)//如果一个都不能插
 82         return -1;
 83     if(n-s+1-temp<num)//如果空位小于要插的数目,改下要插的数目
 84         num=n-s+1-temp;
 85     int l=s;
 86     int r=n;
 87     int mid,d;
 88     int f=-1;
 89     while(r>=l)//二分
 90     {
 91         mid=(l+r)/2;
 92         d=mid-s+1-query(s,mid,1);//d为从s到mid的空位数目
 93         if(d>num)
 94         {
 95             r=mid-1;
 96         }
 97         else if(d<num)
 98             l=mid+1;
 99         else//如果空位的数目正好要一个个减
100         {
101             f=mid;//为了保存第一个能够满足该数目空位的位置
102             r=mid-1;
103         }
104     }
105     return f;
106 }
107 int main()
108 {
109     int i,j,test,x,y,d,m;
110     scanf("%d",&test);
111     while(test--)
112     {
113         scanf("%d%d",&n,&m);
114         n--;
115         Build(0,n,1);
116         for(i=0;i<m;i++)
117         {
118             scanf("%d%d%d",&d,&x,&y);
119             if(d==1)
120             {
121                 int temp=dive(x,1);//查找插的第一个位置
122                 if(temp==-1)
123                 {
124                     printf("Can not put any one.\n");
125                 }
126                 else
127                 {
128                     int en=dive(x,y);//查找插的第二个位置
129                     printf("%d %d\n",temp,en);
130                     update(temp,en,1,1);//更新插满区间
131                 }
132             }
133             else
134             {
135                 printf("%d\n",query(x,y,1));
136                 update(x,y,0,1);//清空区间
137             }
138         }
139         printf("\n");
140     }
141     return 0;
142 }
时间: 2024-10-24 16:50:35

hdu4614的相关文章

hdu4614 Vases and Flowers

Vases and Flowers Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2148    Accepted Submission(s): 836 Problem Description Alice is so popular that she can receive many flowers everyday. She has

【HDU-4614】Vases and Flowers(线段树双查询)

11946317 2014-10-23 09:08:28 Accepted 4614 437MS 2348K rid=11946317" target="_blank" style="color:rgb(26,92,200); text-decoration:none">3340 B G++ KinderRiven #include<cstdio> #include<cstring> #include<iostream&

HDU-4614 Vases and Flowers (线段树区间更新)

题目大意:有n个花瓶,每个花瓶中只能放一朵花.两种操作,一种是从A开始放F朵花,如果有的花瓶中已经有花则跳过这个花瓶,往下一个花瓶放:第二种是将区间[A,B]之间花瓶中的花清空.如果是第一种操作,输出这次放的花的左右端点:如果是第二种操作,输出这次总共清理出了多少支花. 题目分析:建立线段树,节点维护在相应的区间中,没有放入花的花瓶数目.有三种操作:一.查询某个区间中第k个没有插入花的花瓶位置:二.更新区间,使区间全部插入花:三.更新区间,使区间中的花瓶全部清空: 代码如下: # include

hdu4614(线段树+二分)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4614 题意:给定一个区间[0,N-1],初始时每个位置上的数字都是0,可以对其进行以下两种操作: 1.在位置A开始寻找F(如果没有这么多,则有多少个就找多少个)个数值为0的位置,把位置上的数修改为1,并返回第一个和最后一个修改的位置 2.查询区间[a,b]内1的个数,并把区间[a,b]每个位置上的数修改为0 线段树功能:区间更替,区间求和. 分析:sum[rt]表示区间0的个数,二分找出0~L的nu

hdu4614 二分+线段树

题意:给你1-n的花瓶   ,刚开始全是空的,现在有两种操作, 1:从花瓶a开始插入b朵花          如果不能插进去  输出字符串  否则输出最多插入的起点和终点: 2:把a-b的花瓶清空   输出处理花的个数: 结构体数组num[i]表示节点i空瓶的数目 线段树   开始deal函数对整个树初始化,update()更新函数 find()查询区间有多少个空瓶:     对于操作1    关键点是找到起点和终点   这里用二分  在[a,n]进行二分, 先二分起点       注意左右区间

hdu4614 二分法+段树

意甲冠军:给你1-n花瓶   .起初,所有的空,今天,有两种操作模式, 1:从花瓶a開始插入b朵花          假设不能插进去  输出字符串  否则输出最多插入的起点和终点: 2:把a-b的花瓶清空   输出处理花的个数: 结构体数组num[i]表示节点i空瓶的数目 线段树   開始deal函数对整个树初始化,update()更新函数 find()查询区间有多少个空瓶:     对于操作1    关键点是找到起点和终点   这里用二分  在[a,n]进行二分, 先二分起点       注意

Vases and Flowers

hdu4614:http://acm.hdu.edu.cn/showproblem.php?pid=4614 题意:给你n个花瓶,然后有两种操作:1从a开始选择b个花瓶,放进花,输出左端点,右端点 2把a到b之间的花瓶中的花拿走,输出拿走的花的数目. 题解:一看数据范围就知道是线段树,sum维护区间空的花瓶的个数,flag作为lazy标记,如果flag==1表示清空,flag==0表示填满.这一题重要的地方就是二分. 二分找左边的端点,二分找右边的端点.这是这一题的关键,复杂度就是M*logN*