Distance Tree (easy version)
[Link](Problem - E1 - Codeforces)
题意
给你一棵树,边权为 1 1 1, d ( u ) : u 结 点 与 1 号 点 之 间 的 距 离 d(u):u结点与1号点之间的距离 d(u):u结点与1号点之间的距离,设 f ( x ) : 所 有 d ( i ) 中 的 最 大 值 f(x):所有d(i)中的最大值 f(x):所有d(i)中的最大值。
你有 n n n次操作(相互独立)第 i i i次可以添加一条边全为 i i i的边,问你添加完这条边后 f ( x ) f(x) f(x)最小是多少。
数据范围: 2 ≤ n ≤ 3000 2\le n\le 3000 2≤n≤3000
思路
首先加的这条边一定是 ( 1 → u ) (1\to u) (1→u)这样的,因为如果这样不是最优的,设最优解为 ( u → v ) (u\to v) (u→v),那么减少的一定是 v v v的子树的距离,那么我们直接 ( 1 → v ) (1\to v) (1→v)连上一条边,只会让距离更小。
我们可以暴力的枚举这条边连向哪个结点,假设为
u
u
u,那么连接以后的距离
d
(
v
)
d(v)
d(v)会有两种情况:
-
原来从一号点直接连过来的长度设 a v a_v av
-
先从一号点经过加的边连到 u u u再从 u u u到 v v v, 设 u u u到 v v v的距离为 b v b_v bv则当前长度为 b v + x b_v+x bv+x。
如果这样暴力的枚举每一个点,然后再枚举新边长度 x x x,再枚举所有的点判断当前局面的 f ( x ) f(x) f(x)是 O ( n 3 ) O(n^3) O(n3)。
考虑性质发现对于 a v a_v av和 b v + x b_v+x bv+x,当 a v > b v + x a_v>b_v+x av>bv+x的时候这个 d ( v ) d(v) d(v)才会变小,那么对于某个 x x x而言所有的点就会分成两部分,一个是 a v < b v + x a_v<b_v+x av<bv+x的点,这些点还是原来的距离,一个是 a v > b v + x a_v>b_v+x av>bv+x的点,这些点的距离里的最大值就是我们第二部分的解。
随着 x x x增大一定是一些通过第二种走法会变小的点不能变小了,因此发现具有单调性,所以我们可以按照 a v − b v a_v-b_v av−bv给所有的点排序,然后枚举 x x x,找到当前 x x x对应的断点,即起前面是第一部分的解,后面是第二部分的解,对于第二部分的解,我们可以先预处理出排序以后的 b i b_i bi的后缀最大值就可以 O ( 1 ) O(1) O(1)的查找第二部分的解了,对于每个 x x x判断一下当下的最优解就是一二部分大的那个。
复杂度 O ( n 2 ) O(n^2) O(n2)
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
PII a[N];
int dist[N];
int dep[N];
int mx[N], res[N];
bool cmp(PII a, PII b) {
return (a.x - a.y) < (b.x - b.y);
}
void dfs(int u, int fa, int d) {
dist[u] = d;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == fa) continue ;
dfs(j, u, d + 1);
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i < n; i ++) {
int a, b; cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1, 0, 0);
int mmx = 0;
for (int i = 1; i <= n; i ++) dep[i] = dist[i], mmx = max(mmx, dep[i]);
for (int i = 1; i <= n; i ++) res[i] = mmx;
for (int i = 2; i <= n; i ++) {
dfs(i, 0, 0);
for (int j = 1; j <= n; j ++) a[j].x = dep[j], a[j].y = dist[j];
sort(a + 1, a + 1 + n, cmp);
mx[n + 1] = 0;
int p = 1, tmp = 0;
for (int j = n; j; j --) mx[j] = max(mx[j + 1], a[j].y);
for (int k = 1; k <= n; k ++) {
while (p <= n && a[p].x - a[p].y <= k) tmp = max(tmp, a[p].x), p ++;
res[k] = min(res[k], max(k + mx[p], tmp));
}
}
for (int i = 1; i <= n; i ++) cout << res[i] << ' ';
cout << endl;
}
return 0;
}