树的直径
题意:在一棵树上加1条或者2条边使得在保证每条边都遍历了的情况下,回到原点1。问加边后总的花费时间最少是多少,一条边花费的时间为1.加一条边显然在最长链的两个端点之间加一条边就是最省时间的。
如果要加两条边,其中一条还是连最长链,因为每一条边都得遍历,所以第二条边显然不能越过太多的边,要不然还得倒回去遍历一遍。在已经形成一个环的情况下,再加一条边,形成另一个环,这个环只会有两种情况,第一种是有一些边是和第一个环重合的,另一种情况则没有,对于和第一个环重合的部分,我们可以理解为原本只用走一次,但是为了走第二个环,那重合的部分,我们还得退回去走另外一个环,重合的部分仍然得走两次,和原来不变。我们把第一个环所有边的权值设置为-1,再求一次最长链,求出来的是减去与第一个环重合的最长链,两次最长链的和-2(两条新边)就是加上两条边后省下的时间。
#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int MaxnN = 1e5+10;
const int MaxnM = 1e6+10;
const int INF = 0x3f3f3f3f;
const ll LINF = 1e18;
const double eps = 1e-6;
struct Edge {
int u, v, w, next;
} edge[MaxnM];
int h[MaxnN], edge_cnt;
int n, k, rt, max_len;
int son_1[MaxnN], son_2[MaxnN], dp[MaxnN];
// son_1,son_2分别存储当前节点第一长链和第二长链的边,用于对长链做操作
void add(int u, int v) {
edge[edge_cnt].u = u;
edge[edge_cnt].v = v;
edge[edge_cnt].w = 1;
edge[edge_cnt].next = h[u];
h[u] = edge_cnt++;
}
void dfs(int u, int fa) {
for(int i = h[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if(v != fa) {
dfs(v, u);
if(max_len < dp[u]+dp[v]+edge[i].w) {
max_len = dp[u]+dp[v]+edge[i].w;
rt = u;
}
if(son_1[u] == -1 || dp[v] > dp[edge[son_1[u]].v]) {
son_2[u] = son_1[u];
son_1[u] = i;
} else if(son_2[u] == -1 || dp[v] > dp[edge[son_2[u]].v]) {
son_2[u] = i;
}
dp[u] = max(dp[u], dp[v]+edge[i].w);
}
}
}
int main(void)
{
scanf("%d%d", &n, &k);
int u, v;
for(int i = 1; i <= n; ++i) h[i] = -1;
edge_cnt = 0;
for(int i = 0; i < n-1; ++i) {
scanf("%d%d", &u, &v);
add(u, v); add(v, u);
}
int ans = 2*(n-1);
for(int i = 1; i <= n; ++i) son_1[i] = son_2[i] = -1;
for(int i = 1; i <= n; ++i) dp[i] = 0;
max_len = 0;
dfs(1, -1);
ans -= max_len-1;
if(k > 1) {
for(int i = son_1[rt]; i != -1; i = son_1[edge[i].v]) {
edge[i].w = edge[i^1].w = -1;
}
for(int i = son_2[rt]; i != -1; i = son_1[edge[i].v]) {
edge[i].w = edge[i^1].w = -1;
}
for(int i = 1; i <= n; ++i) son_1[i] = son_2[i] = -1;
for(int i = 1; i <= n; ++i) dp[i] = 0;
max_len = 0;
dfs(1, -1);
ans -= max_len-1;
}
printf("%d\n", ans);
return 0;
}
浙公网安备 33010602011771号