树的中心
树 形 d p , 换 根 d p , 必 会 题 目 , 超 级 经 典 , 奈 何 当 初 学 的 时 候 理 解 的 不 深 入 , 还 得 重 新 理 解 树形dp,换根dp,必会题目,超级经典,奈何当初学的时候理解的不深入,还得重新理解 树形dp,换根dp,必会题目,超级经典,奈何当初学的时候理解的不深入,还得重新理解
前 置 知 识 : 树 形 d p 求 树 的 直 径 , 换 根 d p 换 根 d p 可 以 把 O ( N 2 ) 的 做 法 降 低 到 O ( N ) 的 时 间 复 杂 度 , 力 推 ! 前置知识:树形dp求树的直径,换根dp\\ 换根dp可以把O(N^2)的做法降低到O(N)的时间复杂度,力推! 前置知识:树形dp求树的直径,换根dp换根dp可以把O(N2)的做法降低到O(N)的时间复杂度,力推!
给 定 一 根 无 根 树 , 在 树 中 找 到 一 个 点 , 使 得 该 点 到 树 中 其 他 节 点 的 最 远 距 离 最 近 给定一根无根树,在树中找到一个点,使得该点到树中其他节点的最远距离最近 给定一根无根树,在树中找到一个点,使得该点到树中其他节点的最远距离最近
熟练到背过
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#define pb push_back
#define in insert
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e4+10,M=1e9+7;
ll n,m,_;
int h[N],e[N*2],ne[N*2],w[N*2],idx;
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int dis[N],predis[N];//存储从u点向下走的最长和次长路径
int nex[N];//存储从u节点向下的最长路径的下一个点是谁?
int up[N];
int dfs(int u,int fa)
{
// if(h[u]==-1)
// {
// puts("---");
// return 0;//子节点,这句话永远也用不到,是假的
// }
dis[u]=predis[u]=-0x3f3f3f3f;//初始化为负无穷
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa)continue;
int d=dfs(j,u)+w[i];
if(d>=dis[u])
{
predis[u]=dis[u];dis[u]=d;
nex[u]=j;
}
else if(d>predis[u])
{
predis[u]=d;
}
}
if(dis[u]==-0x3f3f3f3f)//判断子节点
{
dis[u]=predis[u]=0;
}
return dis[u];
}
int ans=0x3f3f3f3f;
void dfs_up(int u,int fa)
{
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa)continue;
if(nex[u]==j)//已知父节点,更新子节点
up[j]=max(up[u],predis[u])+w[i];
else
up[j]=max(up[u],dis[u])+w[i];
dfs_up(j,u);
}
}
void solve()
{
cin>>n;
mem(h,-1);
for(int i=0;i<n-1;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
dfs(1,-1);
dfs_up(1,-1);
for(int i=1;i<=n;i++)
{
// cout<<i<<" "<<dis[i]<<" "<<up[i]<<endl;
ans=min(ans,max(dis[i],up[i]));
}
cout<<ans<<endl;
}
int main()
{
solve();
return 0;
}
特别离谱的一件事
请找出下边两端代码的不同,服气了
void dfs_up(int u,int fa)
{
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa)continue;
if(nex[u]==j)//已知父节点,更新子节点
up[j]=max(up[u],predis[u])+w[i];
else
up[j]=max(up[u],dis[u])+w[i];
dfs(j,u);
}
}
void dfs_up(int u, int fa)
{
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j == fa) continue;
if (nex[u] == j) up[j] = max(up[u], predis[u]) + w[i];
else up[j] = max(up[u], dis[u]) + w[i];
dfs_up(j, u);
}
}
换根dp推荐题目:AcWing 287. 积蓄程度
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#define pb push_back
#define in insert
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
typedef unsigned long long ull;
const int N=2e5+10,M=1e9+7;
ll n,m,_;
int h[N],e[N*2],ne[N*2],idx,c[N*2];
void add(int a,int b,int w)
{
e[idx]=b,ne[idx]=h[a],c[idx]=w,h[a]=idx++;
}
int dp[N];
int f[N];
int deg[N];
int ans;
void dfs(int u,int fa)
{
dp[u]=0;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa)continue;
dfs(j,u);
if(deg[j]==1)
dp[u]+=c[i];
else
dp[u]+=min(dp[j],c[i]);
}
}
void dfs_up(int u,int fa)
{
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa)continue;
if(deg[j]==1)
f[j]=dp[j]+c[i];
else
f[j]=dp[j]+min(c[i],f[u]-min(dp[j],c[i]));
dfs_up(j,u);//又犯了同样的错误了
}
}
void solve()
{
mem(h,-1);
idx=0;
ans=0;
mem(deg,0);
cin>>n;
fo(i,0,n-2){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
deg[u]++,deg[v]++;
}
int root=1;
while(root<=n&°[root]==1)root++;
if(root>n)//只有远点和汇点,也就是所有点的度数全是1
{
cout<<c[0]<<endl;
return ;
}
dfs(root,-1);
f[root]=dp[root];
dfs_up(root,-1);
for(int i=1;i<=n;i++)
{
// cout<<i<<" "<<dp[i]<<" "<<f[i]<<endl;
ans=max(ans,f[i]);
}
cout<<ans<<endl;
}
int main()
{
cin>>_;
while(_--)
{
solve();
}
return 0;
}