B - Vases and Flowers HDU - 4614 (线段树+二分)

马上就要参加湘潭邀请赛了,今天刷了一套进阶的线段树来复习复习线段树。希望能拿到牌子~~

日常专题之进阶线段树

专题链接:

https://cn.vjudge.net/contest/300370#overview

A题考虑区间乘,有点难,看别人题解,光pushdown就写了近80行代码。先放弃了

看B题:

Vases and Flowers

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

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]

题意:

有n个花瓶,标号0 ~ n−1。m个操作, 
1AF,表示从A位置开始插FF朵花,遇到有花的花瓶跳过。到最后一个花瓶都还有花剩余,丢弃剩下的花。 
2AB,表示将区间[A,B]内的花瓶全部清空。(A≤B)(A≤B) 
对于每个11操作,输出第一个和最后一个插花的位置,如果一朵花都插不了,输出‘Can not put any one.’;对于每个2操作,输出区间[A,B]内被清空的花瓶的数量。

 

做法:区间保存空花瓶的数量

注意题目这里是(0~n-1)我们建树是1~n

对于操作2 很简单,查询区间A,B里空花瓶的数量num,然后区间长度减去num就是答案。

现在来看看操作1怎么写 对于A,F

先看看[A,N]里的空花瓶是否为零,若为零输出 Can not put any one.

不为零则代表可以插花

那么将第一朵花可以插的位置通过二分区间内的空花瓶数量进行查询位置即可。

最后一朵花可以插的位置通过二分区间内的空花瓶数量进行查询位置即可。

最后更新一下区间内空花瓶 减少的数量

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int sum[N*4],len[N*4],lazy[4*N];
int n,m,t;
void pushdown(int id)
{
	if(lazy[id]!=-1)
	{
		lazy[id<<1]=lazy[id];
		lazy[id<<1|1]=lazy[id];
		sum[id<<1]=len[id<<1]*lazy[id];
		sum[id<<1|1]=len[id<<1|1]*lazy[id];
		lazy[id]=-1;
	}
}
void build(int id,int l,int r)
{
	sum[id]=r-l+1;
	lazy[id]=-1;
	len[id]=r-l+1;
	if(l==r) return ;
	int mid=l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
}
void up(int id,int l,int r,int ql,int qr,int val)
{
	if(ql<=l&&r<=qr)
	{
		lazy[id]=val;
		sum[id]=(r-l+1)*val;
		return ;
	}
	pushdown(id);
	int mid=l+r>>1;
	if(ql<=mid) up(id<<1,l,mid,ql,qr,val);
	if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,val);
	sum[id]=sum[id<<1]+sum[id<<1|1];
}
int qu(int id,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr)
	{
		return sum[id];
	}
	pushdown(id);
	int mid=l+r>>1;
	int ans=0;
	if(ql<=mid) ans+=qu(id<<1,l,mid,ql,qr);
	if(qr>mid) ans+=qu(id<<1|1,mid+1,r,ql,qr);
	return ans;
}
int search(int x,int numb)
{
	int l=x,r=n,ans=-1;
	while(l<=r)
	{
		int mid=l+r>>1;
		int num=qu(1,1,n,x,mid);
		if(num>=numb) 
		{
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	return ans;
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		build(1,1,n);
		int cnt,l,r;
		while(m--)
		{
			scanf("%d%d%d",&cnt,&l,&r);
			if(cnt==1)
			{
				int ql,qr;
				++l;
				int num=qu(1,1,n,l,n);
				if(num==0) printf("Can not put any one.\n");
				else
				{
					ql=search(l,1);
					qr=search(l,min(num,r));
					up(1,1,n,ql,qr,0);
					printf("%d %d\n",ql-1,qr-1);
				}
			}
			else
			{
				++l,++r;
				int num=qu(1,1,n,l,r);
				printf("%d\n",r-l+1-num);
				up(1,1,n,l,r,1);
			}
		}
		puts("");
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙大学ccsu_deer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值