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 ...
随机推荐
- 统计功能和子对象的大小信息查询Bug
I hava below two statement sql: 0. not in subquery select a.schemaname, pg_size_pretty(pg_total_rela ...
- careercup-栈与队列 3.6
3.6 编写程序,按升序对栈进行排序(即最大元素位于栈顶).最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中(如数组).该栈支持如下操作:push.pop.peek和isEmpt ...
- 一个小时成功安装SQL Server 2012图解教程
在安装微软最新数据库SQL Server 2012之前,编者先确定一下安装环境:Windonws 7 SP1,32位操作系统.CPU是2.1GHz赛扬双核T3500,内存2.93GB. 安装SQL S ...
- Linux删除文件Argument list too long问题的解决方案
方法一:使用find find . -name 文件 | xargs rm -f 但文件数量过多,find命令也会出现问题: -bash: /bin/find: Argument list too l ...
- Spring Mvc session拦截器实现
Spring Mvc拦截器实现session过期跳转到登录页面 配置拦截器 <mvc:interceptors> <mvc:interceptor> <mvc:mappi ...
- DataGrid列的合并
/// <summary> /// DataGrid列的合并 /// 注意:1.DataGrid在绑定的时候进行分组和排序,才能让相同的行放在一起 /// 2.方法应用的时机,应该在Dat ...
- Wi-Fi无线网络下行速度超级慢 (5kb/s)之解决方案
转载:http://www.iplaysoft.com/wifi-slow-solution.html 作者:X-Force 转载原因:该文分类提出了多种解决方案,并详述其原因.简洁清晰,可作为参考方 ...
- python基础知识二
对象 python把在程序中用到的任何东西都成为对象. 每一个东西包括数.字符串甚至函数都是对象. 使用变量时只需要给他们赋一个值.不需要声明或定义数据类型. 逻辑行与物理行 物理行是你在编写程序时所 ...
- 个人博客设计:创建Sql数据库操作类。
整体的博客框架如下 数据库操作java类如下 package com.yxq.dao; import java.sql.Connection; import java.sql.DriverManage ...
- 如何:确定调用 ASP.NET 网页的方式
如何:确定调用 ASP.NET 网页的方式 通常有必要了解调用 ASP.NET 网页的方式:是由原始请求 (HTTP GET).回发 (HTTP POST).来自其他页的跨页面发送 (HTTP POS ...