思路:对于输入的 X-Y 边,考虑将该边除去之后形成两棵子树,分别以 X ,Y 为root寻找树的直径(树的两个结点之间的最远长度),这里命名为d1和d2,然后加上 X-Y 边的长度(权值)cost[x][y],每次输入都进行一次运算,并比较,找到最大值即为结果。这里求树的直径可以参考我的关于SPOJ 1437 Longest path in a tree上面的思路及其证明。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
using namespace std;
#define pb push_back
#define fi first
#define se second
#define mk make_pair
#define pil pair<int, ll>
#define rep(i, a, b) for(int i = a; i < b; ++i)
typedef long long ll;
const int maxn = 2020;
bool vis[maxn];
int cost[maxn][maxn];
vector<int>ve[maxn];
int n;
ll ans;
struct Node{
int v;
int dis;
Node(){}
Node(int v, int dis):v(v),dis(dis){}
};
int bfs(int root, int x, int y){
memset(vis,0,sizeof(vis));
ll maxt = 0;
int maxnode = 0;
int cnt = root;
queue<pil>que;
que.push(pil(root, 0));
vis[root] = 1;
while(!que.empty()){
pil c = que.front();
que.pop();
vis[c.fi] = 1;
int s = ve[c.fi].size();
for(int i = 0; i < s; ++i){
int t = ve[c.fi][i];
if(!vis[t]){
if(c.fi==x&&t==y||(c.fi==y&&t==x))continue;
vis[t] = 1;
que.push(pil(t,c.se+cost[c.fi][t]));
if(maxt<c.se+cost[c.fi][t]){
maxt = c.se + cost[c.fi][t];
maxnode = t;
}
}
}
}
ans = max(maxt, ans);
return maxnode;
}
ll work(int root, int x, int y){
ans = 0;
int cnt = bfs(root, x, y);
cnt = bfs(cnt, x, y);
return ans;
}
void build(vector<int> A, vector<int> B, vector<int> L){
int s = A.size();
rep(i,0,maxn)ve[i].clear();///要注意清理干净
rep(i,0,s){
int x = A[i];
int y = B[i];
ll c = (ll)L[i];
x++;y++;
ve[x].pb(y);ve[y].pb(x);
cost[x][y] = cost[y][x] = c;
}
}
class LonglongestPathTree {
public:
long long getLength(vector<int> A, vector<int> B, vector<int> L) {
n=A.size();
build(A,B,L);
ll best = 0;
rep(i,0,n){
int x = A[i];
int y = B[i];
x++; y++;
ll d1 = work(x, x, y);
ll d2 = work(y, x, y);
best = max(best, d1 + d2 + cost[x][y]);
}
return best;
}
};