Loading [MathJax]/jax/output/CommonHTML/jax.js

Loading

2019-2020 XX Open Cup, Grand Prix of Korea J. Parklife 括号序列 树上启发式合并

2019-2020 XX Open Cup, Grand Prix of Korea J. Parklife 括号序列 树上启发式合并

题意

给定x轴上的n条除端点外互不相交的带权值线段

现在可以选择一些线段 求出 任意一条线段被覆盖次数不多于i次(1iN)条件下的最大权值和

1N2500001Si<Ei1e6,1Vi1e9

分析

一般这种保证选择互不相交的条件都可以转化成树上问题 如果两个线段是包含关系转化为祖先关系,这样可以转化为类似括号序列的一棵树。问题相当于转化为树上选择一些顶点,满足任意一条链上的点不超过i个。

有比较显然的贪心:从ii+1总是在原有基础上贪心加一些点。维护每次额外加的那些点,这可以用树形DP来做。

维护以i为根的子树的集合。显然,合并两颗子树的时候是可以直接加的(两子树对应的链独立),第k大的一定和第k的相加。这样就可以用启发式合并+优先队列实现了。

代码

const int maxn = 3e5 + 5;

struct seg{
	int l,r,val;
	friend bool operator < (const seg&a,const seg&b){
		if(a.l == b.l) return a.r > b.r;
		return a.l < b.l;
	}
}a[maxn];


int n;
VI e[maxn];
VI v;
multiset<ll,greater<ll>> s[maxn];

void dfs(int u){
	for(auto v:e[u]) {
		dfs(v);
		if(s[u].size() < s[v].size()) {
			s[u].swap(s[v]);
		}
		multiset<ll,greater<ll>> tmp;
		for(auto vv:s[v]) {
			ll w = *(s[u].begin());
			tmp.insert(w + vv);
			s[u].erase(s[u].begin());
		}
		for(auto vv:tmp)
			s[u].insert(vv);
	}
	if(u) 
		s[u].insert(a[u].val);
}

int main(){
	n = rd();
	VI ans(n + 5);
	for(int i = 1;i <= n;i++)
		a[i].l = rd(),a[i].r = rd(),a[i].val = rd();
	a[0].l = -1e9,a[0].r =1e9;
	sort(a,a + n + 1);
	v.push_back(0);
	for(int i = 1;i <= n;i++){
		while(a[v.back()].r < a[i].r) 
			v.pop_back();
		e[v.back()].push_back(i);
		v.push_back(i);
	}
	dfs(0);
	int p = 1;
	for(auto it:s[0])
		ans[p++] = it;
	for(int i = 1;i <= n;i++){
		ans[i] += ans[i - 1];
		printf("%lld ",ans[i]);
	}
}
posted @   MQFLLY  阅读(103)  评论(0编辑  收藏  举报
编辑推荐:
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
阅读排行:
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 使用 Dify + LLM 构建精确任务处理应用
历史上的今天:
2020-09-12 CodeForces-731F Video Cards 数论,分块
2020-09-12 CodeForces-232B Table 组合数学 DP
点击右上角即可分享
微信分享提示