题面传送门

题意:

桌子上有 \(1\) 个珠子,你要进行 \(n-1\) 次操作,每次操作有以下两种类型:

  1. 拿出一个新珠子,并选择一个桌子上的珠子,在它们之间连一条红线
  2. 选择两个由红线相连的珠子 \(u,v\),并拿出一个新珠子 \(w\),将原来连接 \(u,v\) 的红线断开,并在 \(u,w\) 和 \(v,w\) 之间各连一条蓝线。

显然最后 \(n\) 个珠子会形成一棵由 \(n-1\) 条线的树,给出最终每条线的长度,但你不知道它们的颜色。

你的得分为所有蓝线长度之和,求在所有可能的情况下,你得分的最大值。

\(n \in [2,2\times 10^5]\)

考虑蓝线的性质。由于连成的蓝线就没办法再被断开了,故蓝线连接的三个节点 \(u,w,v\) 在最终的树上也是相邻的。

故原题可以转化为:你可以选择一条三个节点 \(u\to v\to w\) 的链满足边 \((u,v),(v,w)\) 都没被选择,要求选出的边的权值之和的最大值。

树上相邻的三个节点有两种可能,一是爷爷->父亲->儿子,二是儿子->父亲->兄弟。

第二种情况比较复杂。不过我们可以枚举最开始的珠子在最终的树上的编号是多少,也就是钦定一个根节点,这样就不会出现第二种情况(很好理解,如果出现儿子->父亲->兄弟的情况,那我们肯定是先连好儿子->兄弟的边,再插入父亲节点,而由于父亲节点与根节点相连,所以应当是父亲节点先连好才对,所以这种情况不可能出现)

然后就可以 \(dp\) 了。\(dp_{u,0}\) 选好了 \(u\) 的子树中的边,\(u\) 不是某条蓝链的中点的最大权值和。\(dp_{u,1}\) 表示 \(u\) 是某条蓝链的中点的最大权值和。

考虑转移,\(dp_{u,0}\) 比较简单,枚举它的每个儿子 \(v\),有两种情况,要么 \((u,v)\) 间连了条红线,也就是 \(dp_{v,0}\),要么 \((u,v)\) 间连了条蓝线,而由于 \(u\) 不是某条蓝链的中点,所以这条链的连法只可能是 \(u\to v\to v\) 的某个儿子,也就是 \(dp_{v,1}+w\),故 \(dp_{u,0}=\sum\limits_{v\in son_u}\max(dp_{v,0},dp_{v,1}+w)\)

再考虑 \(dp_{u,1}\),显然 \(dp_{u,1}\) 是在 \(dp_{u,1}\) 是在 \(dp_{u,0}\) 的基础上将 \(u\) 与某个儿子 \(v\) 节点之间的边换成蓝边,考虑这一类树形 \(dp\) 的常用套路,枚举这个儿子 \(v\),计算将 \((u,v)\) 之间的边改为蓝边造成的 \(\Delta=dp_{v,0}+w-\max(dp_{v,0},dp_{v,1}+w)\),然后取个 \(\max\) 即可,故 \(dp_{u,1}=dp_{u,0}+\max\limits_{v\in son_u}dp_{v,0}+w-\max(dp_{v,0},dp_{v,1}+w)\)

然后考虑换根,记 \(f_{u}\) 表示以 \(u\) 为根节点的答案,\(out_{i,0/1}\) 表示 \(i\) 子树外的 \(dp\) 值,加法是可逆的,至于 \(\max\), multiset 维护一下即可。这一部分比较套路,具体见代码。

时间复杂度 \(\mathcal O(n\log n)\)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define fi first
  4. #define se second
  5. #define fz(i,a,b) for(int i=a;i<=b;i++)
  6. #define fd(i,a,b) for(int i=a;i>=b;i--)
  7. #define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
  8. #define fill0(a) memset(a,0,sizeof(a))
  9. #define fill1(a) memset(a,-1,sizeof(a))
  10. #define fillbig(a) memset(a,63,sizeof(a))
  11. #define pb push_back
  12. #define ppb pop_back
  13. #define mp make_pair
  14. typedef pair<int,int> pii;
  15. typedef long long ll;
  16. const int MAXN=2e5+5;
  17. int n,to[MAXN<<1],nxt[MAXN<<1],hd[MAXN],cst[MAXN<<1],ec=0;
  18. void adde(int u,int v,int w){
  19. to[++ec]=v;nxt[ec]=hd[u];cst[ec]=w;hd[u]=ec;
  20. }
  21. int dp[MAXN][2],f[MAXN],out[MAXN][2];
  22. void dfs(int x,int fa){
  23. dp[x][1]=-2e9;
  24. for(int e=hd[x];e;e=nxt[e]){
  25. int y=to[e],z=cst[e];if(y==fa) continue;dfs(y,x);
  26. dp[x][0]+=max(dp[y][0],dp[y][1]+z);
  27. dp[x][1]=max(dp[x][1],dp[y][0]+z-max(dp[y][0],dp[y][1]+z));
  28. } dp[x][1]+=dp[x][0];
  29. }
  30. void cgrt(int x,int fa){
  31. int sum=0;
  32. multiset<int> st;st.insert(-2e9);
  33. for(int e=hd[x];e;e=nxt[e]){
  34. int y=to[e],z=cst[e];
  35. if(y==fa){
  36. sum+=max(out[x][0],out[x][1]+z);
  37. st.insert(out[x][0]+z-max(out[x][0],out[x][1]+z));
  38. } else {
  39. sum+=max(dp[y][0],dp[y][1]+z);
  40. st.insert(dp[y][0]+z-max(dp[y][0],dp[y][1]+z));
  41. }
  42. }
  43. for(int e=hd[x];e;e=nxt[e]){
  44. int y=to[e],z=cst[e];if(y==fa) continue;
  45. out[y][0]=sum-max(dp[y][0],dp[y][1]+z);
  46. st.erase(st.find(dp[y][0]+z-max(dp[y][0],dp[y][1]+z)));
  47. out[y][1]=out[y][0]+(*st.rbegin());
  48. st.insert(dp[y][0]+z-max(dp[y][0],dp[y][1]+z));
  49. f[y]=dp[y][0]+max(out[y][0],out[y][1]+z);
  50. cgrt(y,x);
  51. }
  52. }
  53. int main(){
  54. scanf("%d",&n);
  55. for(int i=1;i<n;i++){
  56. int u,v,w;scanf("%d%d%d",&u,&v,&w);
  57. adde(u,v,w);adde(v,u,w);
  58. } dfs(1,0);f[1]=dp[1][0];cgrt(1,0);int ans=0;
  59. for(int i=1;i<=n;i++) ans=max(ans,f[i]);
  60. printf("%d\n",ans);
  61. return 0;
  62. }

洛谷 P3647 [APIO2014]连珠线(换根 dp)的更多相关文章

  1. 洛谷$P3647\ [APIO2014]$连珠线 换根$dp$

    正解:换根$dp$ 解题报告: 传送门! 谁能想到$9102$年了$gql$居然还没写过换根$dp$呢,,,$/kel$ 考虑固定了从哪个点开始之后,以这个点作为根,蓝线只可能是直上直下的,形如&qu ...

  2. 【BZOJ3677】[Apio2014]连珠线 换根DP

    [BZOJ3677][Apio2014]连珠线 Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”.不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色 ...

  3. [换根DP]luogu P3647 [APIO2014]连珠线

    题面 https://www.luogu.com.cn/problem/P3647 不重复地取树中相邻的两条边,每次得分为两条边权和,问最大得分 分析 容易想到状态 f[i][0/1] 分别表示 i ...

  4. Luogu P3647 [APIO2014]连珠线

    题目 换根dp. 显然对于给定的一棵有根树,蓝线都不能拐弯. 设\(f_{u,0}\)表示\(u\)不是蓝线中点时子树内的答案,\(f_{u,1}\)表示\(u\)是蓝线中点时子树内的答案.(以\(1 ...

  5. 并不对劲的bzoj3677:p3647:[APIO2014]连珠线

    题目大意 有一种生成\(n\)个点的树的方法为: 一开始有一个点,\(n-1\)次操作,每次可以有两种操作:1.选一个点,用一条红边将它与新点连接:2.将新点放在一条红边上,新点与这条红边两端点直接的 ...

  6. 【LG3647】[APIO2014]连珠线

    [LG3647][APIO2014]连珠线 题面 洛谷 题解 首先考虑一下蓝线连起来的情况,一定是儿子-父亲-另一个儿子或者是儿子-父亲-父亲的父亲. 而因为一开始只有一个点在当前局面上,将一条红边变 ...

  7. BZOJ 3677 连珠线

    Description 在达芬奇时代,有一个流行的儿童游戏称为连珠线.当然,这个游戏是关于珠子和线的.线是红色或蓝色的,珠子被编号为\(1\)到\(n\).这个游戏从一个珠子开始,每次会用如下方式添加 ...

  8. [Bzoj3677][Apio2014]连珠线(树形dp)

    3677: [Apio2014]连珠线 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 434  Solved: 270[Submit][Status] ...

  9. 题解 [APIO2014]连珠线

    题解 [APIO2014]连珠线 题面 解析 首先这连成的是一棵树啊. 并且\(yy\)一下,如果钦定一个根, 那么这上面的蓝线都是爸爸->儿子->孙子这样的,因为像下图这样的构造不出来: ...

随机推荐

  1. JavaScript04

    分离绑定事件 使用分离方式绑定元素事件可以使用页面元素与JavaScript代码完全分离,有利于代码分工和维护,是目前开发主流,分为两步: 1.获取需要绑定事件的元素 语法:根据id属性值取元素节点 ...

  2. AgileConfig 轻量级配置中心 1.5 发布 - 支持多环境配置

    AgileConfig 从发布到现在,收到不同学的 issue 说需要多环境的支持.也就是一个应用在不同的环境下可以配置不同的配置项.这是一个非常有用的功能,就跟我们开发的时候会设置多个 appset ...

  3. MySQL:怒刷牛客网“sql实战”

    MySQL:怒刷牛客网"sql实战" 在对MySQL有一定了解后,抽空刷了一下 牛客网上的 数据库SQL 实战,在此做一点小小的记录 SQL1 查找最晚入职员工的所有信息 sele ...

  4. [no code][scrum meeting] Alpha 7

    项目 内容 会议时间 2020-04-13 会议主题 OCR技术细节分析 会议时长 30min 参会人员 PM+OCR组成员 $( "#cnblogs_post_body" ).c ...

  5. java监控JVM的内存使用情况等

    以下的程序监控参数的代码,有些是从网络上获取的,此处进行一个记录是为了以后如果要用到方便记录. 1.引入jar包,为了获取一些cpu的使用率等信息 <dependency> <gro ...

  6. FastAPI 学习之路(三十三)操作数据库

    通过创建pydantic模型进行验证提交数据 from pydantic import BaseModel class UserBase(BaseModel): email: str class Us ...

  7. 【做题记录】CF1444A Division

    CF1444A Division 题意: 给定 \(t\) 组询问,每组给两个数 \(p_i\) 和 \(q_i\) ,找出最大的整数 \(x_i\) ,要求 \(p_i\) 可被 \(x_i\) 整 ...

  8. Python import cStringIO ImportError: No module named 'cStringIO'

    From Python 3.0 changelog; The StringIO and cStringIO modules are gone. Instead, import the io modul ...

  9. pl/sql 远程连接oracle数据库问题(TNS:丢失连接)

    前几天还可以连接的,突然就连接失效,别的电脑也连接不上 1.ping 远程数据库的IP,可以ping通. 2.检查服务端的tnsnames.ora文件和本机客户端比较,没问题. 3.查看监听是否启动  ...

  10. 设计模式学习-使用go实现单例模式

    单例模式 定义 优点 缺点 适用范围 代码实现 懒汉模式 饿汉模式 双重检测 sync.Once 参考 单例模式 定义 什么是单例模式:保证一个类仅有一个实例,并提供一个全局访问它的全局访问点. 例如 ...