当前位置: 代码迷 >> 综合 >> 连珠线[APIO2014](换根Dp)
  详细解决方案

连珠线[APIO2014](换根Dp)

热度:48   发布时间:2023-11-19 10:15:12.0

文章目录

  • 题目
  • 思路
  • 思考

题目

Luogu
在达芬奇时代,有一个流行的儿童游戏称为连珠线。当然,这个游戏是关于珠子和线的。线是红色或蓝色的,珠子被编号为 111nnn。这个游戏从一个珠子开始,每次会用如下方式添加一个新的珠子:
Append(w,v)Append(w, v)Append(w,v):一个新的珠子 www 和一个已经添加的珠子 vvv 用红线连接起来。
Insert(w,u,v)Insert(w, u, v)Insert(w,u,v):一个新的珠子 www 插入到用红线连起来的两个珠子 u,vu,vu,v 之间。具体过程是删去 u,vu,vu,v 之间红线,分别用蓝线连接 u,wu,wu,ww,vw,vw,v
每条线都有一个长度。游戏结束后,你的最终得分为蓝线长度之和。
给你连珠线游戏结束后的游戏局面,只告诉了你珠子和链的连接方式以及每条线的长度,没有告诉你每条线分别是什么颜色。
你需要写一个程序来找出最大可能得分。即,在所有以给出的最终局面结束的连珠线游戏中找出那个得分最大的,然后输出最大可能得分。
1≤N≤2?1051\le N\le 2\cdot10^51N2?105

思路

题目理解了好久。。。
发现没有这样的
在这里插入图片描述
因为我们确定一开始的球之后,只会存在 fa?u?vfa-u-vfa?u?v 的连边
于是可以考虑枚举一开始的球,然后当 fa?ufa-ufa?u 这条边被占用只有当 uuu 为蓝线中点
于是可以列出 dpdpdp 定义:
f[u][0]f[u][0]f[u][0] : uuu 子树内 uuu 不作为蓝线中点的最大长度
f[u][1]f[u][1]f[u][1] : uuu 子树内 uuu 作为蓝线中点的最大长度
注意 f[u][1]f[u][1]f[u][1] 的答案会在 fafafa 那里计算,所以对于根节点是没有 f[u][1]f[u][1]f[u][1]
考虑转移

f[u][0]=∑v∈sonumax(f[v][0],f[v][1]+wuv)f[u][0]=\sum_{v\in son_u}max(f[v][0],f[v][1]+w_{uv})f[u][0]=vsonu??max(f[v][0],f[v][1]+wuv?)

然后对于 f[u][1]f[u][1]f[u][1] 我们可以以 f[u][0]f[u][0]f[u][0] 为基础转移,有:

f[u][1]=f[u][0]+max(f[v][0]+wuv?max(f[v][0],f[v][1]+wuv))f[u][1]=f[u][0]+max(f[v][0]+w_{uv}-max(f[v][0],f[v][1]+w_{uv}))f[u][1]=f[u][0]+max(f[v][0]+wuv??max(f[v][0],f[v][1]+wuv?))

也就是减去某个儿子,再加这个新的贡献
但是为了方便转移,我们写成这样

f[u][0]=∑v∈sonumax(f[v][0],f[v][0]+f[v][1]+wuv)f[u][0]=\sum_{v\in son_u}max(f[v][0],f[v][0]+f[v][1]+w_{uv})f[u][0]=vsonu??max(f[v][0],f[v][0]+f[v][1]+wuv?)

然后对于 f[u][1]f[u][1]f[u][1] 我们可以以 f[u][0]f[u][0]f[u][0] 为基础转移,有:

f[u][1]=max(f[v][0]+wuv?max(f[v][0],f[v][0]+f[v][1]+wuv))f[u][1]=max(f[v][0]+w_{uv}-max(f[v][0],f[v][0]+f[v][1]+w_{uv}))f[u][1]=max(f[v][0]+wuv??max(f[v][0],f[v][0]+f[v][1]+wuv?))

这样 f[u]f[u]f[u] 的两种状态就互不干扰了(不这样好像很难写)
我们的答案就是 f[root][0]f[root][0]f[root][0]
如果枚举根的话则是 O(n2)O(n^2)O(n2)
考虑换根 DpDpDp
在这里插入图片描述
由于 f[u][1]f[u][1]f[u][1]fa?ufa-ufa?u 的答案是在 fafafa 时候算的,
我们可以假设根节点也有 f[u][1]f[u][1]f[u][1] 的状态方便转移
现在 f[u][0]f[u][0]f[u][0] 是以 uuu 为根的最大值
我们可以先算出 vvvf[u][0]f[u][0]f[u][0] 的贡献

d=max(f[v][0],f[v][0]+f[v][1]+wuv)d=max(f[v][0],f[v][0]+f[v][1]+w_{uv})d=max(f[v][0],f[v][0]+f[v][1]+wuv?)

在考虑以 vvv 为根:

f[v][0]=f[v][0]+max(f[u][0]?d,f[u][0]?d+f[u][1]+wuv)f[v][0]=f[v][0]+max(f[u][0]-d,f[u][0]-d+f[u][1]+w_{uv})f[v][0]=f[v][0]+max(f[u][0]?d,f[u][0]?d+f[u][1]+wuv?)

f[v][1]=max(f[v][1],f[u][0]?d+wuv?max(f[u][0]?d,f[u][0]?d+f[u][1]+wuv))f[v][1]=max(f[v][1],f[u][0]-d+w_{uv}-max(f[u][0]-d,f[u][0]-d+f[u][1]+w_{uv}))f[v][1]=max(f[v][1],f[u][0]?d+wuv??max(f[u][0]?d,f[u][0]?d+f[u][1]+wuv?))

但发现这里 f[u][1]f[u][1]f[u][1] 可能是由 vvv 转移过来的
于是要保留最大和次大记为 f[u][1]f[u][1]f[u][1]f[u][2]f[u][2]f[u][2]
为了简便我们记

Mx=max(f[u][0]?d,f[u][0]?d+f[u][1]+wuv)Mx=max(f[u][0]-d,f[u][0]-d+f[u][1]+w_{uv})Mx=max(f[u][0]?d,f[u][0]?d+f[u][1]+wuv?)

则有

f[v][1]=max(f[v][1],f[u][0]?d+wuv?Mx)f[v][1]=max(f[v][1],f[u][0]-d+w_{uv}-Mx)f[v][1]=max(f[v][1],f[u][0]?d+wuv??Mx)

然后最大值次大值讨论一下即可

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<bitset>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
    int f=1,x=0;char c=getchar();while(c<'0'||'9'<c){
    if(c=='-')f=-1;c=getchar();}while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();return f*x;
}
#define MAXN 200000
#define mp make_pair
#define INF 2000000001
int n;//不为中点 为中点最大/次大转移 为根最大 
int f[MAXN+5][3],g[MAXN+5];
vector<pair<int,int> > G[MAXN+5];
void DFS1(int u,int fa){
    f[u][0]=0,f[u][1]=f[u][2]=-INF;for(int i=0;i<(int)G[u].size();i++){
    int v=G[u][i].first,w=G[u][i].second;if(v==fa) continue;DFS1(v,u);int Mx=max(f[v][0],f[v][0]+f[v][1]+w);f[u][0]+=Mx;if(f[v][0]+w-Mx>f[u][1])f[u][2]=f[u][1],f[u][1]=f[v][0]+w-Mx;else if(f[v][0]+w-Mx>f[u][2])f[u][2]=f[v][0]+w-Mx;}return ;
}
int ans;
void DFS2(int u,int fa){
    ans=max(ans,f[u][0]);for(int i=0;i<(int)G[u].size();i++){
    int v=G[u][i].first,w=G[u][i].second;if(v==fa) continue;int d=max(f[v][0],f[v][0]+f[v][1]+w),Mx;if(f[v][0]+w-d==f[u][1])Mx=max(f[u][0]-d,f[u][0]-d+f[u][2]+w);elseMx=max(f[u][0]-d,f[u][0]-d+f[u][1]+w);f[v][0]+=Mx;if(f[u][0]-d+w-Mx>f[v][1])f[v][2]=f[v][1],f[v][1]=f[u][0]-d+w-Mx;else if(f[u][0]-d+w-Mx>f[v][2])f[v][2]=f[u][0]-d+w-Mx;DFS2(v,u);}return ;
}
int main(){
    n=read();for(int i=1;i<n;i++){
    int u=read(),v=read(),w=read();G[u].push_back(mp(v,w)),G[v].push_back(mp(u,w));}DFS1(1,0);//for(int i=1;i<=n;i++)// printf("%d %d %d\n",f[i][0],f[i][1],f[i][2]);DFS2(1,0);printf("%d\n",ans);return 0;
}

思考

这种题换根时候容易被绕晕,可以用这种方式思考:
1.理清变量含义
2.去除 vvvuuu 的贡献
3.尝试将 uuu 改为 vvv 的子树
4.分类讨论转移
注意状态转移时还要尽量让对于同一 uuu 的状态转移互不影响