洛谷 P3586 [POI2015] Logistyka 题解

更多文章可以在本人的个人小站:https://kaiserwilheim.github.io 查看。
转载请注明出处。


思路

这道题想让我们维护一个数列,支持对其的修改与询问。

题目给出了两种操作:

  1. U k a 将序列中第 k k k 个数修改为 a a a
  2. Z c s 在这个序列上,每次选出 c c c 个正数,并将它们都减去 1 1 1,询问能否进行 s s s 次操作。

回答询问的思路是这个样子的:

我们假设在这个数列里面,KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲ 0,s \) 范围内的数有 x x x 个,KaTeX parse error: Undefined control sequence: \[ at position 1: \̲[̲ s, \infty \) 范围内的数有 y y y 个。

如果 x + y < c x+y < c x+y<c 的话就绝对不行,直接返回 NIE

我们贪一下心,反正题目询问的是可行性,不如就先让着 y y y 个数先顶上。

如果这 y y y 个数都顶上去之后就可以完成任务,甚至还有些富余,就可以直接返回 TAK
而如果 y < c y < c y<c,那么我们就需要继续往下讨论。

我们考虑让剩下的数顶上去。

如果这些数字的和小于 s × c s \times c s×c,那就绝对完不成任务。
反之则一定完得成任务。

QED.


所以,我们需要维护两个信息,一是大于某个数的数有多少个,二是大于某个数的所有数之和。

我们可以使用树状数组。

但是我不会,所以就用动态开点权值线段树了。

我们考虑结构体里面存什么:

首先我们需要存区间左右端点(按个人情况)和左右儿子。
我们还需要维护区间内数的个数。

为了不多写数据结构,我也将第二个要求写进了线段树里面。

于是我的结构体长的是这个样子:

struct SegTree
{
   
	int l, r;
	int ls, rs;
	ll sum;
	ll tot;
}

其中 sum 维护的是当前区间内数的个数,tot 维护的是当前区间内所有数的和。两者同时维护,但是查询的时候是分开的。

线段树部分代码:

struct SegTree
{
   
	int l, r;
	int ls, rs;
	ll sum;
	ll tot;
}tr[N << 3];
int idx;
void segadd(int p, int pos, ll k)
{
   
	if(tr[p].l == tr[p].r)
	{
   
		tr[p].sum += k;
		tr<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值