题意
一颗有 个结点的数树,每条边有w的花费,可以随意删除一条边,删除之后剩下2棵树,要使这2棵树其中最大的2点距离 最小
思路
首先肯定是删除原树直径中的点,因为删去其他边,那么最长的还是直径,所以删去直径的边才有可能减少距离,可以先把直径起始点s、t 找出来,然后依次枚举删去直径上的边之后剩余2颗子树的最长路径。
分别以s和t为根维护一个dp[u]表示以u为根的数里面的最长路径,然后删除u,v连着的边的时候我们就可以直接通过dp[u](左)和 dp[v] (右) 来更新答案.
vector会被卡建图,链式前向星ok的
code
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 1e6+10;
#define IOS ios::sync_with_stdio(0)
template <typename T>
inline T read(){T sum=0,fl=1;int ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
for(;isdigit(ch);ch=getchar())sum=sum*10+ch-'0';
return sum*fl;}
template <typename T>
inline void write(T x) {static int sta[35];int top=0;
do{sta[top++]= x % 10, x /= 10;}while(x);
while (top) putchar(sta[--top] + 48);}
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}
else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
const ll mod = 1e9+7;
struct edg{
int to,val,next;
}e[man*2];
int head[man],cnt;
int dp[man][2];//表示以u为根这颗树的最长路径
int dis[man],fa[man];
int dis_[man][2];//表示与u最远的链
int maxx,max_id,s,t;
void add(int u,int v,int w){
e[++cnt].next = head[u];
e[cnt].to = v;
e[cnt].val = w;
head[u] = cnt;
}
void dfs1(int u,int f){//处理出直径的端点
for(int i = head[u];~i;i = e[i].next){
int v = e[i].to;
if(v==f)continue;
dis[v] = dis[u] + e[i].val;
if(dis[v]>maxx){
maxx = dis[v];
max_id = v;
}
dfs1(v,u);
}
}
void dfs(int u,int f,int op){
fa[u] = f;
int maxx1 = 0,maxx2 = 0;
dp[u][op] = dis_[u][op] = 0;
for(int i = head[u];~i;i = e[i].next){
int v = e[i].to,w = e[i].val;
if(v==f)continue;
dfs(v,u,op);
int tp = dis_[v][op]+w;
dis_[u][op] = max(dis_[u][op],tp);
if(tp>maxx1){//维护2个最长链和次长链
maxx2 = maxx1;
maxx1 = tp;
}else if(tp>maxx2)maxx2 = tp;
dp[u][op] = max(dp[u][op],dp[v][op]);//也许这颗树的最长路径不经过根节点
}
dp[u][op] = max(dp[u][op] , maxx1 + maxx2);//最长路径经过根节点。
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int n;
cin >> n;
memset(head,-1,sizeof(head));
for(int i = 1;i < n;i++){
int u,v,w;
cin >> u >> v >> w;
add(u,v,w);
add(v,u,w);
}
maxx = -1,max_id = 1;
dis[1] = 0;
dfs1(1,0);
maxx = -1;
s = max_id;
dis[s] = 0;
dfs1(max_id,0);
t = max_id;
//找出s,t
dfs(t,0,0);
dfs(s,0,1);
//s为根,t为根求一遍dp
int ans = INT_MAX;
while(t!=s){//枚举直径的边。
ans = min(ans, max(dp[fa[t]][0],dp[t][1]));
t = fa[t];
}
cout << ans << endl;
return 0;
}