2019年杭电多校第三场 1011题Squrirrel(HDU6613+树DP)

题目链接

传送门

题意

给你一棵无根树,要你寻找一个根节点使得在将一条边权变为\(0\)后,离树根最远的点到根节点的距离最小。

思路

本题和求树的直径很像,不过要记得的东西有点多,且状态也很多。

\(fi[u][0]\)表示在\(u\)这个结点不删边沿着子树方向能到达的最远距离,\(se[u][0]\)为第二远,\(th[u][0]\)为第三远,\(fa[u][0]\)表示沿着父亲方向能到达的最远距离,第二维为\(1\)表示删一条边能到达的距离。

不删边的转移和求树的直径转移方程基本上是一样的,就不再说明。

首先从以\(u\)为根的子树中删除一条边,能到达的最远距离的最小值为\(fi[u][1]=min(fi[v][0],max(fi[v][1],se[v][0])+w)\),\(v\)为\(u\)沿着\(v\)往子树方向走是最远的,也就是说它有三种状态:

  • 删除与\(v\)连接的边能到达的最远距离,在\(u\)的所有儿子结点中,你不删与\(v\)相连的边而删其他的边,那么从子树方向能到达的最远距离仍然是最远距离,不会产生任何影响,肯定不是最优解。
  • 不删除与\(v\)连接的边而在以\(v\)为根的子树中删除一条边能到达的最远距离,注意删除了最远距离的路径上的一条边后原来的次远距离可能变成了最远距离。

次远距离的最小值一样的转移方法,至于对于\(u\)在删除一条边后\(fi[u][1]\)与\(se[u][0]\)的大小关系我们暂时先不考虑。

上面的转移方程只能处理从子树方向的转移,却不能处理沿着父亲结点方向能到达的最远距离,因此我们需要再进行一次\(dfs\)来进行状态转移。

假设当前已经处理出了父亲结点\(u\)沿着其父亲结点在不删边的情况下不沿着\(v\)这个方向所能到达的最远距离\(fa[u][0]\)和删边的最远距离\(fa[u][1]\),那么子结点\(v\)沿着\(u\)所能到达的最远距离的转移:

  • 当\(v\)走是\(u\)沿着子树走能到达的最远距离,那么\(fa[v][0]=max(fa[u][0],se[u][0])+w\),也就是从\(u\)沿着其父亲结点所能到达的最远距离与沿着其子结点所能到达的次远距离两者中最远的转移过来。\(fa[v][1]=min(max(fa[u][0], se[u][0]), min(max(fa[u][1], se[u][0]), max(fa[u][0], max(se[u][1], th[u][0]))) + ed[i].w)\),删除\(u,v\)之间的边所能到达的最远距离与不删除\(u,v\)之间的边所能到达的最远距离,因为删除一条边之后次远距离并不一定比第三远的距离远因此这两者之间也要取个\(max\)。
  • 当\(v\)走是\(u\)沿着子树走能到达的次远、第三远的转移方程和原理类似。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std; typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL; #define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 2e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL; int t, n, tot, u, v, w, ans, idx;
int head[maxn], fa[maxn][3], d[maxn];
int idx1[maxn], idx2[maxn], idx3[maxn];
int fi[maxn][3], se[maxn][3], th[maxn][3]; struct edge {
int v, w, next;
}ed[maxn*2]; void add(int u, int v, int w) {
ed[tot].v = v;
ed[tot].w = w;
ed[tot].next = head[u];
head[u] = tot++;
} void dfs1(int u, int p) {
for(int i = head[u]; ~i; i = ed[i].next) {
int v = ed[i].v;
if(v == p) continue;
dfs1(v, u);
d[v] = ed[i].w;
if(fi[v][0] + ed[i].w > fi[u][0]) {
th[u][0] = se[u][0];
idx3[u] = idx2[u];
se[u][0] = fi[u][0];
idx2[u] = idx1[u];
idx1[u] = v;
fi[u][0] = fi[v][0] + ed[i].w;
} else if(fi[v][0] + ed[i].w > se[u][0]) {
th[u][0] = se[u][0];
idx3[u] = idx2[u];
se[u][0] = fi[v][0] + ed[i].w;
idx2[u] = v;
} else if(fi[v][0] + ed[i].w > th[u][0]) {
th[u][0] = fi[v][0] + ed[i].w;
idx3[u] = v;
}
}
fi[u][1] = min(fi[idx1[u]][0], max(fi[idx1[u]][1], se[idx1[u]][0]) + d[idx1[u]]);
se[u][1] = min(fi[idx2[u]][0], max(fi[idx2[u]][1], se[idx2[u]][0]) + d[idx2[u]]);
} void dfs2(int u, int p) {
int tmp = min(max(fa[u][1], fi[u][0]), max(fa[u][0], max(fi[u][1], se[u][0])));
if(tmp < ans) ans = tmp, idx = u;
else if(tmp == ans && u < idx) ans = tmp, idx = u;
for(int i = head[u]; ~i; i = ed[i].next) {
int v = ed[i].v;
if(v == p) continue;
if(idx1[u] == v) {
fa[v][0] = max(fa[u][0], se[u][0]) + ed[i].w;
fa[v][1] = min(max(fa[u][0], se[u][0]), min(max(fa[u][1], se[u][0]), max(fa[u][0], max(se[u][1], th[u][0]))) + ed[i].w);
} else {
fa[v][0] = max(fa[u][0], fi[u][0]) + ed[i].w;
if(idx2[u] == v) {
fa[v][1] = min(max(fa[u][0], fi[u][0]), min(max(fa[u][1], fi[u][0]), max(fa[u][0], max(fi[u][1], th[u][0]))) + ed[i].w);
} else {
fa[v][1] = min(max(fa[u][0], fi[u][0]), min(max(fa[u][1], fi[u][0]), max(fa[u][0], max(fi[u][1], se[u][0]))) + ed[i].w);
}
}
dfs2(v, u);
}
} int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif // ONLINE_JUDGE
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
tot = 0;
for(int i = 1; i <= n; ++i) {
head[i] = -1;
d[i] = idx1[i] = idx2[i] = idx3[i] = 0;
for(int j = 0; j < 2; ++j) {
fi[i][j] = se[i][j] = th[i][j] = fa[i][j] = 0;
}
}
for(int i = 1; i <= n - 1; ++i) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
dfs1(1, 0);
ans = inf, idx = 1;
dfs2(1, 0);
printf("%d %d\n", idx, ans);
}
return 0;
}
上一篇:RAD Studio XE5破解补丁及方法


下一篇:Squire – 简洁的 HTML5 富文本编辑器