【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,杪):-个新的珠子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

1 3 4 0

1 4 1 5

1 5 2 0

Sample Output

60

HINT

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

树形dp。

确定根之后,之后出现蓝色一定是父子孙的关系。dp一次,然后O(1)换根即可(记录最大和第二大即可)。

(这题如果直接记录三种状态不定根dp会出现不合法的:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#define M 200005
#define inf 0x3f3f3f3f
using namespace std;
int ans,tot,h[M],n;
struct edge
{
    int y,ne,v;
}e[M*2];
struct data
{
    int k,v;
};
struct DP
{
    int v;
    data d[3];
}f[M][2];
void Addedge(int x,int y,int v)
{
    e[++tot].y=y;
    e[tot].ne=h[x];
    e[tot].v=v;
    h[x]=tot;
}
void Upd(data &a,data &b,int x,int v)
{
    if (v>=a.v)
    {
        b=a;
        a.v=v,a.k=x;
    }
    else if (v>b.v)
        b.v=v,b.k=x;
}
void dp(int x,int fa)
{
    f[x][1].d[1].v=f[x][1].d[2].v=-inf;
    f[x][0].v=0;
    for (int i=h[x];i;i=e[i].ne)
    {
        int y=e[i].y;
        if (y==fa) continue;
        dp(y,x);
        int k;
        if (f[y][1].v+f[y][1].d[1].v+e[i].v>f[y][0].v)
            k=f[y][1].v+f[y][1].d[1].v+e[i].v;
        else k=f[y][0].v;
        f[x][0].v+=k;
        f[x][1].v+=k;
        Upd(f[x][1].d[1],f[x][1].d[2],y,-k+f[y][0].v+e[i].v);
    }
}
void dfs(int x,int fa)
{
    ans=max(ans,f[x][0].v);
    for (int i=h[x];i;i=e[i].ne)
    {
        int y=e[i].y;
        if (y==fa) continue;
        DP a=f[y][0],b=f[y][1];
        int p=max(f[y][0].v,f[y][1].v+f[y][1].d[1].v+e[i].v);
        int kk=f[x][0].v-p;
        int k1;
        if (f[x][1].d[1].k==y) k1=2;
        else k1=1;
        int k=max(kk,f[x][1].v-p+f[x][1].d[k1].v+e[i].v);
        f[y][0].v+=k;
        f[y][1].v+=k;
        Upd(f[y][1].d[1],f[y][1].d[2],x,-k+kk+e[i].v);
        dfs(y,x);
        f[y][0]=a,f[y][1]=b;
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        int x,y,v;
        scanf("%d%d%d",&x,&y,&v);
        Addedge(x,y,v),Addedge(y,x,v);
    }
    dp(1,0);
    ans=-inf;
    dfs(1,0);
    cout<<ans<<endl;
    return 0;
}

感悟:

通过枚举根来简化dp

时间: 2024-10-13 03:12:13

【BZOJ 3677】 [Apio2014]连珠线的相关文章

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

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

[BZOJ3677][Apio2014]连珠线

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

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,杪):

字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串

Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,为逝查回文子串的最大出现值. Sample Input [样例输入l] abacaba [样例输入2] www Sample Output [样例输出l] 7 [样例输出2] 4 HINT 一个串是回文的,当且仅当它从左

BZOJ 3676: [Apio2014]回文串 回文串自动机

裸的回文串自动机 3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 504  Solved: 152 [Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s

【斜率DP】BZOJ 3675:[Apio2014]序列分割

3675: [Apio2014]序列分割 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 1066  Solved: 427[Submit][Status][Discuss] Description 小H最近迷上了一个分割序列的游戏.在这个游戏里,小H需要将一个长 度为N的非负整数序列分割成k+l个非空的子序列.为了得到k+l个子序列, 小H将重复进行七次以下的步骤: 1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的 序列一一也就

bzoj 3676: [Apio2014]回文串 回文自动机

3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 844  Solved: 331[Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,