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

3677: [Apio2014]连珠线



Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 434  Solved: 270
[Submit][Status][Discuss]

Description


在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”。不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色。游戏 
开始时,只有1个珠子,而接下来新的珠子只能通过线由以下两种方式被加入: 
1.Append(w,杪):-个新的珠子w和一个已有的珠子杪连接,连接使用红线。 
2.Insert(w,u,v):-个新的珠子w加入到一对通过红线连接的珠子(u,杪) 
之间,并将红线改成蓝线。也就是将原来u连到1的红线变为u连到w的蓝线与W连到V的蓝线。 
无论红线还是蓝线,每条线都有一个长度。而在游戏的最后,将得到游戏的 
最后得分:所有蓝线的长度总和。 
现在有一个这个游戏的最终结构:你将获取到所有珠子之间的连接情况和所 
有连线的长度,但是你并不知道每条线的颜色是什么。 
你现在需要找到这个结构下的最大得分,也就是说:你需要给每条线一个颜 
色f红色或蓝色),使得这种连线的配色方案是可以通过上述提到的两种连线方式 
操作得到的,并且游戏得分最大。在本题中你只需要输出最大的得分即可。

Input


第一行是一个正整数n,表示珠子的个数,珠子编号为1刭n。 
接下来n-l行,每行三个正整数ai,bi(l≤ai10000),表示有一条长度为ci的线连接了珠子ai和珠子bi。

Output


输出一个整数,为游戏的最大得分。

Sample Input


5
1 2 10
1 3 40
1 4 15
1 5 20

Sample Output


60 

HINT


数据范围满足1≤n≤200000。

分析:


一开始以为定义状态f[i][0/1]表示第i个点是不是中心点乱树形dp就可以了,结果考完只有10分

原因:这个题加入有顺序,任何时刻加入的点都是一个联通块。

这样我们就要枚举根节点,并且合并只能合并 父-子-孙。

然后复杂度是O(n^2)的。

我们可以优化一下换根,不用每次换根都去枚举,如果每次只枚举当前根节点没当过根的儿子,会重新dp的只有两个点,换根复杂度O(1)

所以总复杂度O(n)

然后一开始用了vector啥的,bzoj上过了,cena上一首凉凉送给stl,被迫看了别人的代码改出来QAQ

AC代码:


# include <iostream>
# include <cstdio>
using namespace std;
const int N = 3e5 + 12;
const int inf = 0x3f3f3f3f;
int head[N],dt,n,ans,f1[N],f2[N],g[N];
struct Edge{
    int to,nex,w;
}edge[N << 1];
void AddEdge(int u,int v,int w)
{
    edge[++dt] = (Edge){v,head[u],w};
    head[u] = dt;
}
void dfs(int u,int pre)
{
    f1[u] = f2[u] = -inf;int t;
    for(int i = head[u];i;i = edge[i].nex)
    {
        if(edge[i].to == pre)continue;
        dfs(edge[i].to,u);
        t = g[edge[i].to] + edge[i].w - max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
        if(t > f1[u])f2[u] = f1[u],f1[u] = t;
        else if(t > f2[u])f2[u] = t;
        g[u] += max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
    }
}
void Dfs(int u,int pre)
{
    ans = max(ans,g[u]);int s,t,c;
    for(int i = head[u];i;i = edge[i].nex)
    {
        if(edge[i].to == pre)continue;
        s = g[u] - max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
        t = g[edge[i].to] + edge[i].w - max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
        if(f1[u] == t)c = f2[u];else c = f1[u];
        g[edge[i].to] += max(s,s + c + edge[i].w);
        t = s + edge[i].w - max(s,s + c + edge[i].w);
        if(t > f1[edge[i].to])f2[edge[i].to] = f1[edge[i].to],f1[edge[i].to] = t;
        else if(t > f2[edge[i].to])f2[edge[i].to] = t;
        Dfs(edge[i].to,u);
    }
}
int main()
{
    freopen("beads.in","r",stdin);
    freopen("beads.out","w",stdout);
    scanf("%d",&n);int x,y,z;
    for(int i = 1;i < n;i++)
    {
        scanf("%d %d %d",&x,&y,&z);
        AddEdge(x,y,z);AddEdge(y,x,z);
    }
    dfs(1,-1);Dfs(1,-1);
    printf("%d\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/lzdhydzzh/p/8809053.html

时间: 2024-10-13 07:08:37

[Bzoj3677][Apio2014]连珠线(树形dp)的相关文章

[BZOJ3677][Apio2014]连珠线

试题描述 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做"连珠线".不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色.游戏开始时,只有1个珠子,而接下来新的珠子只能通过线由以下两种方式被加入:1.Append(w,v):一个新的珠子w和一个已有的珠子v连接,连接使用红线. 2.Insert(w,u,v):一个新的珠子w加入到一对通过红线连接的珠子(u,v)之间,并将红线改成蓝线.也就是将原来u连到1的红线变为u连到w的蓝线与W连到V的蓝线. 无论红线还是蓝线

【BZOJ 3677】 [Apio2014]连珠线

3677: [Apio2014]连珠线 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 119 Solved: 60 [Submit][Status][Discuss] Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做"连珠线".不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色.游戏 开始时,只有1个珠子,而接下来新的珠子只能通过线由以下两种方式被加入: 1.Append(w,杪):-个新

APIO2014 连珠线

题目链接:戳我 换根DP 由于蒟蒻不会做这个题,所以参考了大佬. 本来想的是有三种情况,一种是该节点不作为两个蓝线的中点(我们称这种不是关键节点),一种是该节点作为关键点.连两个子节点,一种是作为关键节点.一个连子节点一个连父亲节点. 然后有一个不换根的树形DP,但是正确性emmm尚待商榷. 对于一个这样的图-- 我们可以发现,如果想要连起来的话,我们需要不止一个根节点,而这与题目中提到的每次加入一个节点不符. 所以我们考虑换根.这样的话我们发现,就只有两种情况了--一种是该节点不作为关键节点,

Luogu P3647 [APIO2014]连珠线

题目 换根dp. 显然对于给定的一棵有根树,蓝线都不能拐弯. 设\(f_{u,0}\)表示\(u\)不是蓝线中点时子树内的答案,\(f_{u,1}\)表示\(u\)是蓝线中点时子树内的答案.(以\(1\)为根的情况下) 那么显然有\(f_{u,0}=\sum\limits_{v\in son_u}\max(f_{v,0},f_{v,1}+d_v)\). (\(son_u\)表示\(u\)的儿子集合,\(d_u\)表示\((u,fa_u)\)的长度) 但是\(f_{u,1}\)如何求? 我们这样考

bzoj3677【APIO2014】连珠线

3677: [Apio2014]连珠线 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 204  Solved: 115 [Submit][Status][Discuss] Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做"连珠线".不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色.游戏 开始时,只有1个珠子,而接下来新的珠子只能通过线由以下两种方式被加入: 1.Append(w,杪):

HDU 2196 Computer 树形DP经典题

链接:http://acm.hdu.edu.cn/showproblem.php? pid=2196 题意:每一个电脑都用线连接到了还有一台电脑,连接用的线有一定的长度,最后把全部电脑连成了一棵树,问每台电脑和其它电脑的最远距离是多少. 思路:这是一道树形DP的经典题目.须要两次DFS,第一次DFS找到树上全部的节点在不同子树中的最远距离和次远的距离(在递归中进行动态规划就可以),第二次DFS从根向下更新出终于答案.对于每次更新到的节点u,他的最远距离可能是来自u的子树,或者是u的父亲节点的最远

HDU 5758 Explorer Bo(树形DP)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5758 [题目大意] 给出一棵树,每条路长度为1,允许从一个节点传送到任意一个节点,现在要求在传送次数尽量少的情况下至少经过每条路一遍啊,同时最小化走过的路程总长度.输出路程总长度. [题解] 首先,对于传送次数尽量少这个条件,我们很容易发现,当且仅当每次出发点和终止点都是叶节点的时候,是最少的,当然在叶节点无法两两匹配的时候,再多走一条链. 然后就是叶节点的匹配问题,使得匹配后的叶节点连线覆盖全

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi