【解题报告】HDU-4614 Vases and Flowers 线段树+二分

题目大意:给出n个点从0~n-1排成一条线,然后又m条命令,k=1就是从某个点开始插多少话进去,k=2就是把l到r之间的花扔掉。。换成程序员的语言就是k=1就查询第一个插入点和最后一个插入点,k=2就查询区间插了多少花。

查询差了多少花没什么难度,关键是找第一个和最后一个插入点,显然用二分查找。

#include <iostream>
#include <string.h>
#include<algorithm>
#include <cstdio>
using namespace std;
#define lc n << 1
#define rc n << 1 | 1
const int maxn = 50010;

struct seg {
	int l, r, sum;//节点sum存这段区间还有多少空位,或说能插多少花
	int lazy;
}t[maxn << 2];
inline int len(int n) { return t[n].r - t[n].l + 1; }
inline void push_up(int n)
{
	t[n].sum = t[lc].sum + t[rc].sum;
}
inline void push_down(int n)
{
	int x = t[n].lazy;
	t[lc].sum = (x == 1 ? 0 : len(lc));
	t[rc].sum = (x == 1 ? 0 : len(rc));
	t[lc].lazy = t[rc].lazy = x;
	t[n].lazy = 0;
}
void build(int n, int l, int r)
{
	t[n].l = l;t[n].r = r;t[n].lazy = 0;
	if (l == r)
	{
		t[n].sum = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(lc, l, mid);
	build(rc, mid + 1, r);
	push_up(n);
}

void update(int n, int l, int r,int a)//a=1是插花,a=-1是扔花
{
	if (l > t[n].r || r < t[n].l)return;
	if (l <= t[n].l&&r >= t[n].r)
	{
		t[n].sum = (a == 1 ? 0 : len(n));
		t[n].lazy = a;
		return;
	}
	if (t[n].lazy)
		push_down(n);
	update(lc, l, r, a);
	update(rc, l, r, a);
	push_up(n);
}

int query(int n, int l, int r)
{
	if (l > t[n].r || r < t[n].l)
		return 0;
	if (l <= t[n].l&&r >= t[n].r)
		return t[n].sum;
	if (t[n].lazy != 0)push_down(n);
	return query(lc, l, r) + query(rc, l, r);
}

void solve(int l,int r, int f)
{
	int x = query(1, l, r);//先查询从l开始一共能插多少花
	if (x == 0)
	{
		cout << "Can not put any one." << endl;
		return;
	}
	else if (x < f) { f = x; }//这一步很关键!去除之后会错,原因看二分部分
	int ql = l, qr = r, mid;
	while (ql != qr)//找第一个插入点
	{
		mid = (ql + qr) >> 1;
		x = query(1, ql, mid);
		if (x >= 1)
			qr = mid;
		else
			ql = mid + 1;
	}
	cout << ql << ' ';
	ql = l, qr = r;
	while (ql != qr)//找最后一个
	{
		mid = (ql + qr) >> 1;
		x = query(1, ql, mid);
		if (x >= f)//因为这一句话所以f要等于min(f,x)
		{
			qr = mid;
		}
		else
		{
			update(1, ql, mid, 1);
			f -= x;//如果左子树的sum<f那么把左子树插满花
			ql = mid + 1;
		}
	}
	update(1, qr, qr, 1);//qr这个点可能没更新到
	printf("%d\n",qr);
}
int main()
{
	int T, n, m, c, f, b;
	cin >> T;
	while (T--)
	{
		scanf("%d%d",&n,&m);
		build(1, 0, n - 1);
 		while (m--)
		{
			scanf("%d%d%d",&c,&b,&f);
			if (c == 1)solve(b, n - 1, f);
			else
			{
				int q = query(1, b, f);
				printf("%d\n",(f - b + 1) - q);
				update(1, b, f, -1);
			}
		}
	printf("\n");
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值