hdu4614(二分查询线段树)

/*
translation:
	程序媛经常收到花:),现在有若干花瓶,以及对应的若干个操作,1 a b表示程序媛将从a号花瓶起,从左往右在每个空的
	花瓶里放置1朵花,遇到花瓶里有花的就跳过。2 a b表示程序媛将清空a~b号
	花瓶。对每个操作输出对应的信息,1操作输出最开始放置花和最后放置花的花瓶编号。2操作输出a~b之间的花朵数目。
solution:
	线段树+二分
	很容易想到对1操作二分找寻两个位置。其它还是常规写法。思路简单,编码麻烦。WA了若干次才写对!
note:
	# 放到最后一个花瓶后如果手里还有花就丢掉,题意理解错误了ORZ。
	# 二分好容易写错啊。
	# 这段码效率较低,g++能过,c++就TLE
	# 线段树码真心长,明天绝逼不训线段树了。括弧笑:)
date:
	2016.12.1
*/
#include <iostream>
#include <cstdio>

using namespace std;
const int maxn = 50000 + 5;

int s[maxn*4], e[maxn*4];
int sum[maxn*4], lazy[maxn*4];
int n, m, res_flower;

void build(int l, int r, int o)
{
	s[o] = l;
	e[o] = r;
	sum[o] = 0;
	lazy[o] = -1;

	if(l != r){
		int m = (l + r) >> 1;
		build(l, m, o << 1);
		build(m+1, r, o << 1 | 1);
	}
}

void push_down(int o, int num)
{
	int lc = o << 1, rc = o << 1 | 1;
	if(lazy[o] != -1){
		lazy[lc] = lazy[rc] = lazy[o];
		sum[lc] = lazy[lc] * (num - (num >> 1));
		sum[rc] = lazy[rc] * (num >> 1);
		lazy[o] = -1;
	}
}

inline void push_up(int o)
{
	sum[o] = sum[o << 1] + sum[o << 1 | 1];
}

void update(int x, int l, int r, int o)	//将l~r的元素改成x
{
	if(s[o] == l && e[o] == r){
		lazy[o] = x;
		sum[o] = x * (r - l + 1);
		return;
	}
	if(s[o] == e[o])	return;

	push_down(o, e[o]-s[o]+1);

	int m = (s[o] + e[o]) >> 1;
	if(r <= m)	update(x, l, r, o << 1);
	else if(l > m)	update(x, l, r, o << 1 | 1);
	else{
		update(x, l, m, o << 1);
		update(x, m+1, r, o << 1 | 1);
	}

	push_up(o);
}

int query(int l, int r, int o)
{
	if(s[o] == l && e[o] == r){
		return sum[o];
	}
	push_down(o, e[o]-s[o]+1);

	int res = 0;
	int m = (s[o] + e[o]) >> 1;

	if(r <= m)	res += query(l, r, o << 1);
	else if(l > m)	res += query(l, r, o << 1 | 1);
	else{
		res += query(l, m, o << 1);
		res += query(m+1, r, o << 1 | 1);
	}
	return res;
}

int find_pre(int a, int f)
{
	int lb = a, ub = n, mid;
	for(int i = 0; i < 50; i++){
		mid = (lb + ub) >> 1;
		int len = n - mid + 1;
		if(len - query(mid, n, 1) >= f)	lb = mid;
		else	ub = mid;
	}
	return mid;
}

int find_suf(int st, int f)	//验证从st位置到mid位置是否有f个空花瓶
{
	int lb = st, ub = n, mid;
	for(int i = 0; i < 50; i++){
		mid = (lb + ub) >> 1;
		int len = mid - st + 1;
		if(len - query(st, mid, 1) >= f)	ub = mid;
		else	lb = mid;
	}
	return ub;
}

int find_suf2(int st, int f)
{
	int lb = st, ub = n, mid;
	for(int i = 0; i < 50; i++){
		mid = (lb + ub) >> 1;
		int len = mid - st + 1;
		if(len - query(st, mid, 1) < f)	lb = mid;
		else	ub = mid;
	}
	return ub;
}

int main()
{
	//freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--){
		scanf("%d%d", &n, &m);
		build(1, n, 1);
		res_flower = 0;

		int op, a, b;
		while(m--){
			scanf("%d", &op);
			if(op == 1){
				scanf("%d%d", &a, &b);
				a++;
				int len = n - a + 1;
				if(len-query(a, n, 1) == 0)	printf("Can not put any one.\n");
				else{
					int pre = find_pre(a, len - query(a, n, 1)), suf;
					if(n - pre + 1 - query(pre, n, 1) < b)	suf = find_suf2(a, len - query(a, n, 1));
					else	suf = find_suf(a, b);

					printf("%d %d\n", pre-1, suf-1);
					update(1, pre, suf, 1);
				}
			}else{
				scanf("%d%d", &a, &b);
				a++;	b++;
				printf("%d\n", query(a, b, 1));
				update(0, a, b, 1);
			}
		}
		printf("\n");
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值