hdu 4614 线段树+二分

7 篇文章 0 订阅
6 篇文章 0 订阅

题意:n个花瓶,m个操作,花瓶里面有的有花,有的是空的。1操作是从a开始往右放b朵花,花瓶有了的不放,跳过,直到a右边都放满了花,多余的扔了。输出本次放花的起始位置


求和操作可以用线段树解决,操作1的放置的起始位置,通过二分求就可以

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define maxn 100009

using namespace std;

int n, m, a[maxn * 8], is[8 * maxn];

void build (int x, int l, int r)
{
	if (l == r)
	{
		a[x] = 1;
		is[x] = -1;
		return;
	}
	int mid = (l + r) >> 1;
	build (2 * x, l, mid);
	build (2 * x + 1, mid + 1, r);
	a[x] = a[2 * x] + a[2 * x + 1];
	is[x] = -1;
	return;
}

int ask (int x, int l, int r, int la, int ra)
{
	if (l > ra || r < la)
		return 0;
	if (la <= l && r <= ra)
	{
		if (is[x] == 0)
			return 0;
		if (is[x] == 1)
			return r - l + 1;
		return a[x];
	}
	int mid = (l + r) >> 1;
	if (is[x] != -1)
	{
		is[2 * x] = is[2 * x + 1] = is[x];
		a[2 * x] = is[x] * (mid - l + 1);
		a[2 * x + 1] = is[x] * (r - mid);
		a[x] = is[x] * (r - l + 1);
		is[x] = -1;
	}
	return ask (2 * x, l, mid, la, ra) + ask (2 * x + 1, mid + 1, r, la, ra);
}

void set (int x, int l, int r, int la, int ra, int color)
{
	//printf ("========== set (%d %d) %d %d ==%d\n", l, r, la, ra, color);
	if (l > ra || r < la)
		return;
	if (la <= l && r <= ra)
	{
		is[x] = color;
		a[x] = color * (r - l + 1);
		return;
	}
	int mid = (l + r) >> 1;
	if (is[x] != -1)
	{
		is[2 * x] = is[2 * x + 1] = is[x];
		a[2 * x] = is[x] * (mid - l + 1);
		a[2 * x + 1] = is[x] * (r - mid);
		a[x] = is[x] * (r - l + 1);
		is[x] = -1;
	}
	set (2 * x, l, mid, la, ra, color);
	set (2 * x + 1, mid + 1, r, la, ra, color);
	a[x] = a[2 * x] + a[2 * x + 1];
}

void print (int x, int l, int r)
{
//	printf (" %d    (%d, %d) == %d  ->   %d\n", x, l, r, a[x], is[x]);
	if (l == r)
		return;
	int mid = (l + r) >> 1;
	print (2 * x, l, mid);
	print (2 * x + 1, mid + 1, r);
}

void debug ()
{
	printf ("==================================================\n");
	print (1, 1, n);
}

int main ()
{
	int ti;
	cin >> ti;
	rep (f1, 1, ti)
	{
		cin >> n >> m;
		build (1, 1, n);
		while (m--)
		{
			//printf (" (ask 1-n) %d\n", ask (1, 1, n, 1, n));
			//debug ();
			int col, x, y;
			scanf ("%d%d%d", &col, &x, &y);
			if (col == 1)
			{
				x++;
				int Max = ask (1, 1, n, x, n), L, R;
				//printf ("Max -----------------------------------%d\n", Max);
				if (Max == 0)
				{
					printf ("Can not put any one.\n");
					continue;
				}

				int l = x, r = n;
				while (l <= r)
				{
					int mid = (l + r) >> 1;
					int p = ask (1, 1, n, x, mid);
					if (p == 1)
						L = mid;
					if (p >= 1)
						r = mid - 1;
					else
						l = mid + 1;
				}
				/*if (Max <= y)
				{
					printf ("%d %d\n", L - 1, n - 1);
					set (1, 1, n, L, n, 0);
					continue;
				}*/

				//last
				l = L, r = n;
				while (l <= r)
				{
					int mid = (l + r) >> 1;
					int p = ask (1, 1, n, L, mid);
					//printf ("er fen %d ----    %d\n", mid, p);
					if (p == min (y, Max) )
						R = mid;
					if (p >= min (y, Max) )
						r = mid - 1;
					else
						l = mid + 1;
				}
				printf ("%d %d\n", L - 1, R - 1);
				set (1, 1, n, L, R, 0);
				//printf ("ask ------ %d\n", ask (1, 1, n, L, R));
			}
			else
			{
				x++, y++;
				printf ("%d\n", y - x + 1 - ask (1, 1, n, x, y));
				set (1, 1, n, x, y, 1);
			}
		}
		
			printf ("\n");
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值