BZOJ 3677 连珠线
Description
在达芬奇时代,有一个流行的儿童游戏称为连珠线。当然,这个游戏是关于珠子和线的。线是红色或蓝色的,珠子被编号为\(1\)到\(n\)。这个游戏从一个珠子开始,每次会用如下方式添加一个新的珠子:
\(Append(w, v)\):一个新的珠子\(w\)和一个已经添加的珠子\(v\)用红线连接起来。
\(Insert(w, u, v)\):一个新的珠子\(w\)插入到用红线连起来的两个珠子\(u,v\)之间。具体过程是删去\(u,v\)之间红线,分别用蓝线连接\(u,w\)和\(w,v\)。
每条线都有一个长度。游戏结束后,你的最终得分为蓝线长度之和。
给你连珠线游戏结束后的游戏局面,只告诉了你珠子和链的连接方式以及每条线的长度,没有告诉你每条线分别是什么颜色。
你需要写一个程序来找出最大可能得分。即,在所有以给出的最终局面结束的连珠线游戏中找出那个得分最大的,然后输出最大可能得分。
Input
第一行是一个正整数\(n\),表示珠子的个数,珠子编号为\(1\)到\(n\)。
接下来\(n-1\)行,每行三个正整数\(a_{i},b_{i}(1 \le a_{i} \le 10000)\),表示有一条长度为\(c_{i}\)的线连接了珠子\(a_{i}\)和珠子\(b_{i}\)。
Output
输出一个整数,为游戏的最大得分。
Sample Input
5
1 2
1 3 4 0
1 4 1 5
1 5 2 0
Sample Output
60
HINT
数据范围满足\(1 \le n \le 200000\)。
这题我开始YY树形dpYY了很久,都被自己拍死了,后来是hmr大神(跪烂)告诉了结论的。
对于某种合法的红蓝线分布情况,一定满足蓝线分布在\(son_{i},i,father_{i}\)之间。
于是\(O(n^{2})\)dp就出来了。每次换根进行dp即可。状态\(f_{i,1}\)表示以\(i\)为根的子树,\(i\)是蓝线的终点所能得到的最大收益;相反\(f_{i,0}\)表示以\(i\)为根的子树,\(i\)不是蓝线的中点所能够得到的最大收益。
令\(cost_{i}\)表示\(i\)与\(father_{i}\)所连的边的权值大小,那么就有转移$$f_{i,0}=\sum_{j \in son_{i}}max(f_{j,0},f_{j,1}+cost_{j})$$
\]
正解就是只进行一遍dp,每次\(O(1)\)进行换根转移。
我们在第一次dp的时候,记录一下\(dp_{i,j,0}\)和\(dp_{i,j,1}\)的值,表示\(i\)不考虑\(j\)这个儿子的\(f_{i,0/1}\)(\(dp{i,j,1}\)的用\(-max(f_{j,0},f_{j,1}+cost_{j})+f_{j,0}+cost_{j})\;(j \in son_{i})\)的最大值和次大值维护即可)。
每次换根从父亲换到儿子,只会修改两个点的\(f\)值,将这两个点用\(dp\)再转移一遍即可。
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std;
#define inf (1<<29)
#define maxn (500010)
int n,side[maxn],toit[maxn*2],next[maxn*2],len[maxn],f[maxn][2],cnt,ans,father[maxn],cost[maxn];
vector <int> son[maxn],dp[maxn][2],best[maxn];
inline void add(int a,int b,int c) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; len[cnt] = c; }
inline void ins(int a,int b,int c) { add(a,b,c); add(b,a,c); }
inline void update(int &a,int b) { if (b < 0) return; if (b > a) a = b; }
inline void dfs(int now)
{
f[now][1] = -inf; f[now][0] = 0;
int fb = -inf,sb = -inf;
for (int i = side[now];i;i = next[i])
{
if (toit[i] == father[now]) continue;
cost[toit[i]] = len[i]; father[toit[i]] = now; dfs(toit[i]);
f[now][0] += max(f[toit[i]][0],f[toit[i]][1]+len[i]);
if (-max(f[toit[i]][0],f[toit[i]][1]+len[i])+f[toit[i]][0]+len[i]>fb)
sb = fb,fb = -max(f[toit[i]][0],f[toit[i]][1]+len[i])+f[toit[i]][0]+len[i];
else if (-max(f[toit[i]][0],f[toit[i]][1]+len[i])+f[toit[i]][0]+len[i] > sb)
sb = -max(f[toit[i]][0],f[toit[i]][1]+len[i])+f[toit[i]][0]+len[i];
}
f[now][1] = f[now][0] + fb;
for (int i = side[now],tmp,key;i;i = next[i])
{
if (toit[i] == father[now]) continue;
son[now].push_back(toit[i]);
dp[now][0].push_back(tmp = f[now][0] - max(f[toit[i]][0],f[toit[i]][1]+len[i]));
if (-max(f[toit[i]][0],f[toit[i]][1]+len[i])+f[toit[i]][0]+len[i] == fb) key = sb; else key = fb;
dp[now][1].push_back(tmp + key); best[now].push_back(key);
}
}
inline void work(int now,int id)
{
f[now][0] = dp[now][0][id];
f[now][1] = dp[now][1][id];
if (father[now])
{
f[now][0] += max(f[father[now]][0],f[father[now]][1]+cost[now]);
f[now][1] = f[now][0];
int key = max(best[now][id],-max(f[father[now]][0],f[father[now]][1]+cost[now])+f[father[now]][0]+cost[now]);
f[now][1] += key;
}
update(ans,f[son[now][id]][0]+max(f[now][0],f[now][1]+cost[son[now][id]]));
}
inline void Dp(int now)
{
for (int nn = son[now].size(),i = 0;i < nn;++i)
work(now,i),Dp(son[now][i]);
}
int main()
{
freopen("3677.in","r",stdin);
freopen("3677.out","w",stdout);
scanf("%d",&n);
for (int i = 1,a,b,c;i < n;++i) scanf("%d %d %d",&a,&b,&c),ins(a,b,c);
dfs(1); update(ans,f[1][0]);
Dp(1);
printf("%d",ans);
fclose(stdin); fclose(stdout);
return 0;
}
BZOJ 3677 连珠线的更多相关文章
- [Bzoj3677][Apio2014]连珠线(树形dp)
3677: [Apio2014]连珠线 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 434 Solved: 270[Submit][Status] ...
- bzoj3677: [Apio2014]连珠线
Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”.不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色.游戏 开始时,只有1个珠子,而接下来新的 ...
- 【BZOJ3677】[Apio2014]连珠线 换根DP
[BZOJ3677][Apio2014]连珠线 Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”.不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色 ...
- 【LG3647】[APIO2014]连珠线
[LG3647][APIO2014]连珠线 题面 洛谷 题解 首先考虑一下蓝线连起来的情况,一定是儿子-父亲-另一个儿子或者是儿子-父亲-父亲的父亲. 而因为一开始只有一个点在当前局面上,将一条红边变 ...
- 题解 [APIO2014]连珠线
题解 [APIO2014]连珠线 题面 解析 首先这连成的是一棵树啊. 并且\(yy\)一下,如果钦定一个根, 那么这上面的蓝线都是爸爸->儿子->孙子这样的,因为像下图这样的构造不出来: ...
- bzoj 3677: [Apio2014]连珠线【树形dp】
参考:http://www.cnblogs.com/mmlz/p/4456547.html 枚举根,然后做树形dp,设f[i][1]为i是蓝线中点(蓝线一定是父子孙三代),f[i][0]为不是,转移很 ...
- BZOJ 1610 连线游戏
BZOJ不允许除以0. #include<iostream> #include<cstdio> #include<cstring> #include<cstd ...
- APIO2014 连珠线
题目链接:戳我 换根DP 由于蒟蒻不会做这个题,所以参考了大佬. 本来想的是有三种情况,一种是该节点不作为两个蓝线的中点(我们称这种不是关键节点),一种是该节点作为关键点.连两个子节点,一种是作为关键 ...
- Luogu P3647 [APIO2014]连珠线
题目 换根dp. 显然对于给定的一棵有根树,蓝线都不能拐弯. 设\(f_{u,0}\)表示\(u\)不是蓝线中点时子树内的答案,\(f_{u,1}\)表示\(u\)是蓝线中点时子树内的答案.(以\(1 ...
随机推荐
- PureMVC(JS版)源码解析(十):Controller类
这篇博客我们继续讲解PureMVC的三大核心类(View/Controller/Model)——Controller类.根据PureMVC模块设计,Controller类保存所有的Comm ...
- android开发之PreferenceScreen使用详解
是在惭愧,学习android也有一段时间了,今天才是第一次接触PreferenceScreen.记录下来,与大家分享. 本文参考:http://lovezhou.iteye.com/blog/1020 ...
- Java基础知识强化之网络编程笔记02:Socket通信原理图解
1. Socket (1)Socket套接字 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字 (2)Socket原理机制: • 通信两端都有Socket. • 网 ...
- Linux下rsync增加SSH端口号的用法
rsync默认使用SSH的22号端口,为了安全起见,很多机器更改了SSH默认的端口号,对应rsync命令的用法为: rsync -e 'ssh -p 1234' username@hostname:S ...
- java Date日期去掉时分秒
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String s = sdf.format(new Date() ...
- 核心运营报表无线端数据,pv,uv相关数据,从9月1号开始就没了,为什么?
问题现象截图 核心运营报表 从获取数据的api的地址可以看出: http://data.51buy.com/json.php?biz=statistic&mod=OrderKeyData&am ...
- JS0热身运动
热身热身小知识点: JS中如何获取元素: 1 通过ID名称来获取:document get element by id -->document.getElementById() 2 .... ...
- [转]JavaScript 的同源策略
同源策略限制了一个源(origin)中加载文本或脚本与来自其它源(origin)中资源的交互方式. 同源定义 如果两个页面拥有相同的协议(protocol),端口(如果指定),和主机,那么这两个页面就 ...
- css hack方法总结
IE6识别:下划线 _ 和 星号 *IE7识别:星号 *IE6-IE10识别: \9 css hack方式,条件注释法<!--[if IE]>这段文字只在IE浏览器显示<![endi ...
- 最新的C#SqlHelper 类苏飞修改版(转载)
/// <summary> /// 类说明:公共的数据库访问访问类 /// 编码日期:2010-4-22 /// 编 码 人:苏飞 /// 联系方式:361983679 Email:[ur ...