L - Computer(HDU2196 ,树形DP,换根法)
题目 :传送门
思路见注释
代码 :
*
换根法dp:
先把无根树化为有根树
第一遍dfs,对于顶点u,求u的子树到u的最大和次大距离
第二遍dfs,将树化为顶点u为根,求u的子树到u的最大距离和次大距离
对于u的最大距离就是u的答案res[u],而u的次大距离是用来儿子换根的时候进行状态转移
*/
#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int inf=0x3f3f3f3f;
const ll N=1e4+10;
const ll mod=1e9+7;
vector<P> g[N];
int dp[N][2];//u的最大值与次大值
int pos[N][2];//u的最大值与次大值的位置
int res[N];
void dfs1(int u,int fa)
{
for(P &p:g[u])
{
int v=p.first,w=p.second;
if(v==fa) continue;
dfs1(v,u);
if(dp[v][0]+w>dp[u][0]){
dp[u][1]=dp[u][0];
pos[u][1]=pos[u][0];
dp[u][0]=dp[v][0]+w;
pos[u][0]=v;
}
else if(dp[v][0]+w>dp[u][1]){
dp[u][1]=dp[v][0]+w;
pos[u][1]=v;
}
}
// printf("u:%d,dp[0]:%d,pos[0]:%d,dp[1]:%d,pos[1]:%d\n",u,dp[u][0],pos[u][0],dp[u][1],pos[u][1]);
}
void dfs2(int u,int fa,int w)
{
int other=0;
if(fa!=u)//再次换根为u,更新最大和次大
{
if(pos[fa][0]!=u)//other代表从父亲到该根的最大与次大
other=dp[fa][0]+w;
else
other=dp[fa][1]+w;
if(other>dp[u][0]){
pos[u][1]=pos[u][0];
dp[u][1]=dp[u][0];
pos[u][0]=fa;
dp[u][0]=other;
}
else if(other>dp[u][1])
{
pos[u][1]=fa;
dp[u][1]=other;
}
}
res[u]=dp[u][0];
for(P &p:g[u])
{
int v=p.first;
if(v==fa) continue;
dfs2(v,u,p.second);
}
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
int n;
while(cin>>n)
{
for(int i=1;i<=n;++i) g[i].clear();
for(int i=2;i<=n;++i){
int w,v;
cin>>v>>w;
g[i].push_back({v,w});
g[v].push_back({i,w});
}
mset(dp,0);
mset(pos,0);mset(res,0);
dfs1(1,1);
dfs2(1,1,0);
for(int i=1;i<=n;++i){
cout<<res[i]<<endl;
}
}
}