題意
一顆有個結點的數樹,每條邊有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;
}