hdu 4614 Vases and Flowers 多校总结

本文深入探讨了线段树的应用技巧,特别是在区间更新操作中如何高效处理数据。通过实例讲解了节点维护、懒惰传播等关键概念,并展示了如何在特定范围内进行有效的数据更新和查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

久违的线段树,好久没敲了,比赛的时候也没心思看,之前卡题卡太久
成段更新,特别之处,有个范围的更新是会超出 n 的值
三个每个节点的三个数据:(需要更新的数据)
(1) 区间内的花数量、
(2) 区间内最左边的空格的编号、

(3) 区间内最右边的空瓶的编号


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int maxn = 105000;
const int inf = 1000000000;
int min( int a, int b ){ return a < b ? a : b; }
int max( int a, int b ){ return a > b ? a : b; }
int del[maxn<<2], sum[maxn<<2], fid[maxn<<2], lid[maxn<<2];
int mov, first, last, num;
void pushdown( int rt, int l, int r )
{
	int len = r - l + 1;
	if( del[rt] == 1 )
	{
		del[rt<<1] = del[rt<<1|1] = del[rt];
		sum[rt<<1] = len - len / 2;
		sum[rt<<1|1] = len / 2;
		lid[rt<<1] = fid[rt<<1] = -1;
		lid[rt<<1|1] = fid[rt<<1|1] = -1;
		del[rt] = 0;
	}
	else if( del[rt] == -1 )
	{
		del[rt<<1] = del[rt<<1|1] = del[rt];
		sum[rt<<1|1] = sum[rt<<1] = 0;
		fid[rt<<1] = l;
		lid[rt<<1] = (l + r) >> 1;
		fid[rt<<1|1] = (l + r) / 2 + 1;
		lid[rt<<1|1] = r;
		del[rt] = 0;
	}
}
void pushup( int rt )
{
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
	fid[rt] = min( min( fid[rt<<1] == -1 ? inf : fid[rt<<1], lid[rt<<1] == -1 ? inf : lid[rt<<1] ), 
			min( fid[rt<<1|1] == -1 ? inf : fid[rt<<1|1], lid[rt<<1|1] == -1 ? inf : lid[rt<<1|1] ) );
	lid[rt] = max( max( fid[rt<<1], lid[rt<<1] ), max( fid[rt<<1|1], lid[rt<<1|1] ) );
	if( fid[rt] == inf )fid[rt] = lid[rt];
}
void build( int l, int r, int rt )
{
	del[rt] = 0;
	sum[rt] = 0;
	fid[rt] = l;
	lid[rt] = r;
	if( l == r )
		return ;
	int m = (l + r) >> 1;
	build( lson );
	build( rson );
}
void update( int L, int R, int sign, int l, int r, int rt )
{
	if( sign == 2 )
	{
		if( L <= l && r <= R )
		{
			del[rt] = -1;
			mov += sum[rt];
			sum[rt] = 0;
			fid[rt] = l;
			lid[rt] = r;
			return ;
		}
	}
	else if( sign == 1 )
	{
		if( L <= l && r - l + 1 - sum[rt] <= num )
		{	
			del[rt] = 1;
			num -= r - l + 1 - sum[rt];
			sum[rt] = r - l + 1;
			if( fid[rt] != -1 && (first == -1 || fid[rt] < first) )
				first = fid[rt];
			if( lid[rt] != -1 && (last == -1 || lid[rt] > last) )
				last = lid[rt];
			fid[rt] = -1;
			lid[rt] = -1;
			return ;
		}
	}
	pushdown( rt, l, r );
	int m = (l + r) >> 1;
	if( sign == 2 )
	{
		if( L <= m )update( L, R, sign, lson );
		if( m < R )update( L, R, sign, rson );
	}
	if( sign == 1 )
	{
		if( m - l + 1 - sum[rt<<1] && L <= m && num > 0 )
			update( L, R, sign, lson );
		if( r - m - sum[rt<<1|1] && num > 0 )
			update( L, R, sign, rson );
	}
	pushup( rt );
}
int main()
{
	int T, n, q, sign, a, b;
	scanf( "%d", &T );
	while( T-- )
	{
		scanf( "%d%d", &n, &q );
		build( 0, n - 1, 1 );
		while( q-- )
		{	
			scanf( "%d%d%d", &sign, &a, &b );
			if( sign == 1 && sum[1] == n )
			{
				puts("Can not put any one.");
				continue;
			}
			if( sign == 2 && a > b )swap( a, b );
			if( sign == 2 )
				mov = 0;
			else
				first = last = -1;
			num = b;
			update( a, b, sign, 0, n - 1, 1 );
			if( sign == 2 )
				printf( "%d\n", mov );
			else
				if( num != b )
					printf( "%d %d\n", first, last );
				else
					puts("Can not put any one.");
		}
		puts("");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值