P3647 [APIO2014]連珠線 題解
阿新 • • 發佈:2022-05-20
首先可以注意到一點:如果這棵樹確定了根節點,那麼所有的藍邊都只能是爺爺-父親-兒子這樣的邊,不可能有兒子-父親-另一個兒子這樣的(建不出來)。
基於上述結論的一個 \(O(n^2)\) dp就是:列舉根節點,設 \(f_{u,0/1}\) 表示 \(u\) 節點子樹中,\(u\) 是否作為某一條藍邊鏈中點的最大藍邊長度。轉移方程說的是:
\[f_{u,0}=\sum_{v\in son_u}\max(f_{v,0},f_{v,1}+w(u,v)) \] \[f_{u,1}=f_{u,0}+\max_{v\in son_u}\{f_{v,0}+w(u,v)-\max(f_{v,0},f_{v,1}+w(u,v))\} \]現在考慮使用換根dp來優化。首先設 \(dp_{u,0/1,v}\)
考慮換根dp的過程:走到 \(v\) 點的時候,\(g_{u,0/1}\) 應該表示的是 \(u\) 除 \(v\) 以外的兒子以及父親合併起來的dp值,這樣在計算以 \(v\) 為根的答案時,只需要將它的父親 \(u\) 也作為一個兒子合併dp值即可。這個方程不難轉移(和上邊是差不多的),然後就做完了。
注意換根dp的邊界有些時候可能會出錯,比如這個題需要尤其注意 \(fa=0\) 時的情況。
點選檢視程式碼
#include<iostream> #include<cstdio> #include<vector> #define pb push_back #define mp std::make_pair #define fi first #define se second typedef std::pair<int,int> pii; inline int max(const int &a,const int &b){return a>b?a:b;} inline int rd(){ int res=0;char c=getchar(); for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar())res=(res<<1)+(res<<3)+(c-'0'); return res; } const int N=2e5+13,INF=0x3f3f3f3f; int n,f[N][2],g[N][2],ans,a[N]; std::vector<int> dp[N][2]; std::vector<pii> e[N]; inline void add_edge(int u,int v,int w){e[u].pb(mp(v,w));} void dfs1(int u,int fa){ f[u][1]=-INF; int mx1=-INF,mx2=-INF,son1=0; for(int i=0,lim=e[u].size();i<lim;++i){ int v=e[u][i].fi,w=e[u][i].se;if(v==fa) continue; dfs1(v,u);a[v]=w; f[u][0]+=max(f[v][0],f[v][1]+w); int tmp=f[v][0]+w-max(f[v][0],f[v][1]+w); if(tmp>mx1) mx2=mx1,mx1=tmp,son1=v; else if(tmp>mx2) mx2=tmp; } if(!son1) return; f[u][1]=f[u][0]+mx1; for(int i=0,lim=e[u].size();i<lim;++i){ int v=e[u][i].fi,w=e[u][i].se; if(v==fa){dp[u][0].pb(0),dp[u][1].pb(0);continue;} dp[u][0].pb(f[u][0]-max(f[v][0],f[v][1]+w)); if(v!=son1) dp[u][1].pb(f[u][1]-max(f[v][0],f[v][1]+w)); else dp[u][1].pb(f[u][0]-max(f[v][0],f[v][1]+w)+mx2); } } void dfs2(int u,int fa){ ans=max(ans,f[u][0]+max(g[fa][0],g[fa][1]+a[u])); for(int i=0,lim=e[u].size();i<lim;++i){ int v=e[u][i].fi;if(v==fa) continue; int mx=dp[u][1][i]-dp[u][0][i]; if(fa){ g[u][0]=dp[u][0][i]+max(g[fa][0],g[fa][1]+a[u]); g[u][1]=g[u][0]+max(mx,g[fa][0]+a[u]-max(g[fa][0],g[fa][1]+a[u])); } else g[u][0]=dp[u][0][i],g[u][1]=dp[u][1][i]; dfs2(v,u); } } int main(){ n=rd(); for(int i=1;i<n;++i){ int u=rd(),v=rd(),w=rd(); add_edge(u,v,w),add_edge(v,u,w); } dfs1(1,0); dfs2(1,0); printf("%d\n",ans); return 0; }