AT_agc009_d [AGC009D] Uninity
这题看完题解后迟迟不下手写代码,因为这道题实在是太厉害了!
考虑对于一棵树手玩这个过程,发现如果一个点要作为中间的一个节点,它肯定会挂上周围的所有点所在的树,当然它之后挂的点除外。这事实上是一个点分树的过程,那么该问题就是求最大深度最小的点分树,发现并不好做。
好在它刚刚告诉我答案是
这个性质貌似可以在考虑两棵树的时候想到,因为要想把两棵树连起来,显然要有一个点能让这两棵树挂在一起,而这两棵树挂的点显然大于这两棵树里的点的点权。
所以现在问题转化了,我们只需要求使得最大值最小的合法的点权分配方式即可。考虑贪心的子树转移,设
直接二进制转移即可。
代码:
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i (l); i <= r; ++ i)
#define rrp(i, l, r) for (int i (r); i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define inf 1000000000
using namespace std;
constexpr int N = 1e5 + 5, M = 310, P = 1e9 + 7;
typedef unsigned long long ull;
typedef long long ll;
inline ll rd () {
ll x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) {
if (ch == '-') f = -1;
ch = getchar ();
}
while (isdigit (ch)) {
x = (x << 1) + (x << 3) + ch - 48;
ch = getchar ();
}
return x * f;
}
void add (int &x, int y) {
(x += y) >= P ? (x -= P) : (x);
}
int qpow (int x, int y) {
int ret = 1;
for (; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P;
return ret;
}
int n;
vector <int> e[N];
int ans, f[N];
void dfs (int u, int fa) {
int s = 0, p = 0;
for (auto v : e[u]) {
if (v == fa) continue;
dfs (v, u);
rep (i, 0, 20) {
if ((s >> i & 1) && (f[v] >> i & 1)) p = max (p, i + 1);
} s |= f[v];
}
while (s >> p & 1) ++ p;
ans = max (ans, p);
f[u] = s;
f[u] |= 1 << p;
f[u] = (f[u] >> p) << p;
}
int main () {
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
n = rd ();
rep (i, 2, n) {
int u = rd (), v = rd ();
e[u].eb (v), e[v].eb (u);
}
dfs (1, 0);
cout << ans;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?