P9130 [USACO23FEB] Hungry Cow P (动态开点线段树+线段树二分)

P9130 [USACO23FEB] Hungry Cow P

动态开点线段树+线段树二分

考虑线段树。

首先区间范围是 [1,1014],而需要的点只有 nlogn 个,所以需要用到动态开点线段树

考虑合并,需要维护每个区间留下的稻草 left 和还没填的空的数量 blank 以及 ans

对于 leftblank 的合并,只有左区间的 left 可以贡献右区间,只有右区间的 blank 可以被消掉,所以写出来

uleft=rsleft+max(0,lsleftrsblank)

ublank=lsblank+max(0,rsblanklsleft)

对于 ans 无法做到 O(1) 维护,这时候可以选择维护更多的信息或者线段树上二分。考虑后者。

首先 lsans 肯定是答案的一部分,接下来就是分讨右区间,考虑构造一个函数 calc(l,r,x) 表示当前在 [l,r] 前面留下 x 个稻草,所以此时左区间贡献给右区间 lsleft

xrls.blank,那么 rrs 的答案只会被 rls 影响,就是 rsansrlsans,并递归 calc(l,mid,x)

否则,rls 的区间被填满,答案可以 O(1) 算出,并递归 calc(mid+1,r,xrlsblank+rlsleft)

每次只会递归一半,所以 calc 的复杂度是 O(logn),总复杂度是 O(nlog2n)

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back

typedef long long i64;
const int N = 10000010, mod = 1000000007, inv2 = 500000004;
i64 tot = 1;
struct seg {
	i64 ls, rs;
	i64 left, blank, ans;
} t[N];
void crea(i64 &u, i64 l, i64 r) {
	if(u) return; 
	u = ++tot;
	t[u].blank = r - l + 1;
	t[u].left = 0;
	t[u].ans = 0;
}
void pushup(i64 u, i64 l, i64 r) {
	i64 mid = (l + r) >> 1;
	t[u].left = std::max(0ll, std::max(0ll, t[t[u].ls].left - std::min(r - mid, t[t[u].rs].blank)) + t[t[u].rs].left);
	t[u].blank = std::max(0ll, std::min(mid - l + 1, t[t[u].ls].blank) + std::max(0ll, std::min(r - mid, t[t[u].rs].blank) - t[t[u].ls].left));
}
i64 query(i64 &u, i64 l, i64 r, i64 x) {
	if(l == r) return (x ? l % mod : t[u].ans);
	i64 mid = (l + r) >> 1;
	if(x <= std::min(mid - l + 1, t[t[u].ls].blank)) return (query(t[u].ls, l, mid, x) + (t[u].ans - t[t[u].ls].ans + mod) % mod) % mod;
	return (((l + mid) % mod * ((mid - l + 1) % mod) % mod * inv2 % mod) + query(t[u].rs, mid + 1, r, x - std::min(mid - l + 1, t[t[u].ls].blank) + t[t[u].ls].left)) % mod;
}
void update(i64 &u, i64 l, i64 r, i64 x, i64 y) {
	crea(u, l, r);
	if(l == r) {
		if(!y) t[u].left = 0, t[u].blank = 1, t[u].ans = 0;
		else t[u].left = y - 1, t[u].blank = 0, t[u].ans = l % mod;
		return;
	}
	i64 mid = (l + r) >> 1;
	if(x <= mid) update(t[u].ls, l, mid, x, y);
	else update(t[u].rs, mid + 1, r, x, y);
	pushup(u, l, r);
	t[u].ans = (t[t[u].ls].ans + query(t[u].rs, mid + 1, r, t[t[u].ls].left)) % mod;
}
i64 n, rt = 1;
void Solve() {
	std::cin >> n;
	t[1].blank = t[0].blank = 2e14;
	for(int i = 1; i <= n; i++) {
		i64 a, b;
		std::cin >> a >> b;
		update(rt, 1, 2e14, a, b);
		std::cout << t[rt].ans << "\n";
	}
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	Solve();

	return 0;
}
posted @   Fire_Raku  阅读(44)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示