[SPOJ - FTOUR2] Free tour II(点分治 + 背包dp + 启发式合并)

SPOJ - FTOUR2 Free tour II

problem

给定一棵树,以及 mmm 个拥挤城市编号,选择一条最多包含 kkk 个拥挤城市的简单路径。

每条边有一个有趣度 www,可正可负。简单路径的价值定义为包含边的有趣度之和。

求最大价值。n≤2e5,∣w∣≤1e4n\le 2e5,|w|\le 1e4n2e5,w1e4

solution

取点作根,计算过根的符合条件的简单路径价值,如果不过根就转化成各个独立子树的子问题。

选取重心作根,点分治。

问题仍然在于怎么计算过根的符合条件的简单路径价值。

暴力的树形 dpdpdpdpi,j:idp_{i,j}:idpi,j:i 子树内拥挤城市为 jjj 的最大路径价值。

每次枚举 iii 的儿子,每次做树上背包,之后再合并,时间复杂度是平方级别的。

dpu,x+dpv,y(x+y≤k)→ansdp_{u,x}+dp_{v,y}(x+y\le k)\rightarrow ansdpu,x+dpv,y(x+yk)ans

dpu,x=max⁡(dpu,x,dpv,x)dp_{u,x}=\max(dp_{u,x},dp_{v,x})dpu,x=max(dpu,x,dpv,x)

考虑优化。

对于第 iii 个儿子而言,如果第 iii 个儿子使用的拥挤城市数量为 jjj,那么前 i−1i-1i1 个儿子的城市拥挤数量可以使用 1∼k−j1\sim k-j1kj

所以可以“前缀和”优化,这里去前缀最大值

dpu,x:dp_{u,x}:dpu,x:i−1i-1i1 个儿子城市拥挤数量使用不超过 xxx 的最大价值。

这样就可以线性枚举 jjj 计算贡献。

最后就是在枚举前 i−1i-1i1 个儿子的拥挤数量问题上。

比如第 ppp 个儿子内部最多可以找到一条路径有 kkk 个拥挤城市,而现在的儿子最多只能有 y(y<k)y(y<k)y(y<k) 个。

但是从第 ppp 个儿子开始就必须枚举完使用 kkk 个拥挤城市,才能将前面儿子的信息覆盖完全。

但是这样的时间复杂度就会飞起。

如果交换现在的儿子和第 ppp 个儿子顺序,那么只用枚举完 yyy 个拥挤城市就已经覆盖了前面儿子的所有路径使用情况。

所以将儿子按照内部最多能找到一条路径有 ddd 个拥挤城市,ddd 升序排序。

相当于只将每个点枚举了一次,这就是启发式合并。

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 200005
#define inf 0x7f7f7f7f
vector < pair < int, int > > G[maxn];
int n, m, k, Max, root, N, ans;
bool crowd[maxn], vis[maxn];
int siz[maxn], f[maxn], g[maxn];
struct node { int d, v, w; }MS[maxn];void dfs( int u, int fa ) {int maxsiz = 0; siz[u] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first;if( vis[v] or v == fa ) continue;else dfs( v, u ), siz[u] += siz[v];maxsiz = max( maxsiz, siz[v] );}maxsiz = max( maxsiz, N - siz[u] );if( maxsiz < Max ) Max = maxsiz, root = u;
}int dfs( int u, int fa, int cnt ) {if( cnt == k ) return cnt;int ret = cnt;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first;if( vis[v] or v == fa ) continue;ret = max( ret, dfs( v, u, cnt + crowd[v] ) );}return ret;
}void dfs( int u, int fa, int val, int cnt ) {if( cnt > k ) return;g[cnt] = max( g[cnt], val );for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, w = G[u][i].second;if( vis[v] or v == fa ) continue;dfs( v, u, val + w, cnt + crowd[v] );}
}void calc( int u ) {if( crowd[u] ) k --;int cnt = 0;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, w = G[u][i].second;if( vis[v] ) continue;MS[++ cnt] = { dfs( v, u, crowd[v] ), v, w };}//计算出v子树内一条路最多能有多少个拥挤城市sort( MS + 1, MS + cnt + 1, []( node x, node y ) { return x.d < y.d; } );//启发式合并for( int i = 1;i <= cnt;i ++ ) {int v = MS[i].v, w = MS[i].w;dfs( v, u, w, crowd[v] ); //计算出v子树内访问x个拥挤城市的最大有趣度/*f[j]:前i-1个子树信息总和 访问j个拥挤城市的最大值g[j]:只针对第i个子树 访问j个拥挤城市的最大值 每次都会在dfn(v,u,w,crowd[v])重新计算显然 g[j]+f[x](0<=x<=k-j) 都可以对最终答案进行贡献这里对f[x]进行前缀max 有jx平方的时间变成j线性实际上x<=MS[i-1].d 要注意这个限制 不然可能会莫须有地更新到不存在的拥挤城市个数 影响f然后将i子树信息合并到i-1子树信息内 即g->f转到下一个子树i+1*/if( i ^ 1 ) {for( int j = 1;j <= MS[i - 1].d;j ++ ) f[j] = max( f[j], f[j - 1] );for( int j = 0;j <= MS[i].d;j ++ ) ans = max( ans, f[min( MS[i - 1].d, k - j )] + g[j] );}for( int j = 0;j <= MS[i].d;j ++ ) f[j] = max( f[j], g[j] ), g[j] = 0;}for( int i = 0;i <= MS[cnt].d;i ++ ) {ans = max( ans, f[i] );f[i] = g[i] = 0;}if( crowd[u] ) k ++;
}void dfs( int u ) {vis[u] = 1;calc( u );for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first;if( vis[v] ) continue;Max = inf, N = siz[v];dfs( v, u );dfs( root );}
}int main() {scanf( "%d %d %d", &n, &k, &m );for( int i = 1, x;i <= m;i ++ ) scanf( "%d", &x ), crowd[x] = 1;for( int i = 1, u, v, w;i < n;i ++ ) {scanf( "%d %d %d", &u, &v, &w );G[u].push_back( { v, w } );G[v].push_back( { u, w } );}Max = inf, N = n;dfs( 1, 0 );dfs( root );printf( "%d\n", ans );return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PKUSC2022 游记

前言 1001822698014095235。 题的难度感觉比去年难不少&#xff0c;主要的体现在于两天的T1都没有之前那么可做了&#xff0c;在信息差的影响下几乎成了两场崩盘场。 由于比赛时间变短的原因&#xff0c;模拟反而比历年简单不少。 遗憾&#xff1a; d1t3的网络流莫名其妙无法…

Acwing 216. Rainbow的信号

Acwing 216. Rainbow的信号 题意&#xff1a; 给你n个数&#xff0c;在这n个数中&#xff0c;等概率地选取两个数l&#xff0c;r&#xff0c;如果l>r,则交换l,r 把信号中的第 l 个数到第 r 个数取出来&#xff0c;构成一个数列 P。 A 部分对话的密码是数列 P 的 xor 和的…

微软开源故事 | 开启 .NET 开源革命

如今&#xff0c;在微软构建开源软件是很正常的一件事——但早在2007年&#xff0c;我开始在微软工作时&#xff0c;情况并非如此。我们花了几年的时间才找到正确的方法&#xff0c;顺利开启了微软的开源之路。但是&#xff0c;如今我们已取得胜利&#xff0c;可以面带微笑地回…

【无码专区9】序列统计(带权并查集 + 前缀和建边 + dp)

因为只有std&#xff0c;没有自我实现&#xff0c;所以是无码专区 主要是为了训练思维能力 solution才是dls正解&#xff0c;但是因为只有潦草几句&#xff0c;所以大部分会有我自己基于正解上面的算法实现过程&#xff0c;可能选择的算法跟std中dls的实现不太一样。 std可能…

Acwing 217. 绿豆蛙的归宿

Acwing 217. 绿豆蛙的归宿 题意&#xff1a; 给出一个有向无环的连通图&#xff0c;起点为 1&#xff0c;终点为 N&#xff0c;每条边都有一个长度。 数据保证从起点出发能够到达图中所有的点&#xff0c;图中所有的点也都能够到达终点。 绿豆蛙从起点出发&#xff0c;走向…

LNOI2022:游记

前言 The world is cruel. 真的为身边的一些人感到可惜… Day -1 PKUSC刚刚考完&#xff0c;然后就要省选了&#xff1f; 板子实在是看的够够的了。 然而还是不想深度做题&#xff0c;看了看APIO的practise&#xff0c;T1写完发现偶数还得特别做&#xff0c;就感觉很麻烦&…

合肥.NET技术社区首次线下聚会全程回顾【多图】

2019年3月16日对于合肥.NET来说是一个特别的日子&#xff0c;因为这是合肥.NET技术社区首次非正式线下聚会&#xff01;这次聚会受场地限制&#xff08;毕竟是聚餐的形式&#xff09;&#xff0c;即使换成了小椅子后&#xff0c;最多也只能容纳24个人&#xff0c;所以还有一些小…

【无码专区10】第K大查询(双向链表 /主席树+st表)

已自我实现&#xff0c;但还是归入无码专区序列。哈哈哈哈哈 对于my idea部分&#xff0c;我的每一个想法都实现了&#xff0c;可供参考。 problem 给定一个 1∼n1\sim n1∼n 的排列和 kkk&#xff0c;求所有 r−l1≥kr-l1\ge kr−l1≥k 的区间 [l,r][l,r][l,r] 中的第 kkk 大…

SignalR第一节-在5分钟内完成通信连接和消息发送

前言首先声明&#xff0c;这又是一个小白从入门到进阶系列。 SignalR 这个项目我关注了很长时间&#xff0c;中间好像还看到过微软即将放弃该项目的消息&#xff0c;然后我也就没有持续关注了&#xff0c;目前的我项目中使用的是自己搭建的 WebSocket &#xff0c;连接管理和消…

P5327 [ZJOI2019]语言(线段树合并、生成树)

解析 只会扫描线树剖的三只log&#xff08;悲 考虑对每个 uuu 考虑合法的 vvv 的集合&#xff0c;必然是一个联通块。 进一步的&#xff0c;观察到这个联通块就是由所有经过 uuu 的路径的端点形成的最小生成树。 我们有一个最小生成树的经典结论&#xff1a;最小生成树边权和…

【学习笔记】信息学竞赛中的概率与期望小结

信息竞赛——概率与期望事件事件的蕴含、包含事件的互斥事件的对立事件的和&#xff08;并&#xff09;事件的积&#xff08;交&#xff09;事件的差概率事件的独立性全概率公式贝叶斯公式概率DP&#xff08;竞赛中的考察&#xff09;期望&#xff08;竞赛中的考察&#xff09;…

Acwing 218. 扑克牌

Acwing 218. 扑克牌 题意&#xff1a; 一副扑克牌(54张)&#xff0c;问得到A 张黑桃、B 张红桃、C 张梅花、D 张方块需要翻开的牌的张数的期望值 E 是多少&#xff1f; 如果翻开的牌是大王或者小王&#xff0c;Admin 将会把它作为某种花色的牌放入对应堆中&#xff0c;使得放…

尝试:Script Lab,快速 O365 开发工具//SL01)

《前言》Script Lab 我希望有一个系列&#xff08;连载&#xff09;&#xff0c;可是我挺担心没偿没有能力去驾驭它。虽然早年前己经接触过&#xff0c;但一直未有下决心开始 Office 365 的开发之旅&#xff0c;虽然一直被光标老师所鼓舞&#xff0c;但是我心有旁骛还没有真正做…

P3710 方方方的数据结构(kd-tree)

解析 写吐了… 一开始觉得线段树分治直接做就行简直是个伞兵题&#xff0c;写完挂掉才想起来线段树分治会打乱操作顺序导致全假… 重构吧&#xff01; 炸裂之下去贺题解&#xff0c;std做法 O(mmlog⁡m)O(m\sqrt m\log m)O(mm​logm) 令人谔谔&#xff0c;但kd-tree做法确实挺…

[POJ 3709] K-Anonymous Sequence(斜率优化dp / 动态维护凸包)

K-Anonymous Sequence看了两年前自己的博客&#xff0c;真的好青涩&#xff0c;连 markdown 都不太会用。 确实观赏感不是很好。 学习真的是慢慢积累的过程&#xff0c;以前感觉理解很困难的事&#xff0c;随着知识的增长&#xff0c;现在都基本悟了。 problem POJ3709 so…

Keiichi Tsuchiya the Drift King

Keiichi Tsuchiya the Drift King 题意&#xff1a; 给定一辆小车长宽分别为 b&#xff0c;a&#xff0c;轨道的圆弧部分半径为 r&#xff0c;圆弧对应的角度为 d&#xff0c;求出小车能通过轨道的最小轨道宽度 w。 题解&#xff1a; 我们考虑小车处于什么状态会使弯道最宽…

AspNet Core 下利用普罗米修斯+Grafana构建Metrics和服务器性能的监控

概述Prometheus是一套开源的监控&报警&时间序列数据库的组合,起始是由SoundCloud公司开发的。该项目有非常活跃的社区和开发人员&#xff0c;目前是独立的开源项目&#xff0c;现在最常见的Kubernetes容器管理系统中&#xff0c;通常也会搭配Prometheus进行监控。prome…

模板:pb_ds指南

科技改变生活 前言 本来一直被畏于巨长的声明&#xff0c;没有学这个东西… 直到 棘手的操作 这道题&#xff0c;pb_ds模拟实现的两个log的做法不仅好写的一批&#xff0c;连时间竟然也把我单log的左偏树爆踩了&#xff1f;&#xff1f;&#xff1f; … 我选择打不过就加入… …

【学习笔记】多重背包相关优化——二进制优化/单调队列优化

多重背包——二进制优化/单调队列优化二进制优化单调队列优化代码都是 POJ1742 的&#xff0c;注意&#xff0c;那道题二进制优化会超时。 普通的多重背包式子&#xff0c;物品个数限制&#xff1a;c[i]c[i]c[i]&#xff0c;单个物品价值 w[i]w[i]w[i]&#xff0c;每个物品的体…

Game of Swapping Numbers

Game of Swapping Numbers 题意&#xff1a; A&#xff0c;B两个数组&#xff0c;让你对A进行k次操作&#xff0c;每次操作为选两个位置的数&#xff0c;进行交换&#xff0c;求最大化的Σ|Ai-Bi| 题解&#xff1a; 以前有做过最小化的情况&#xff0c;就是把每次交换作定量…