Acwing264.权值 (点分治)
考虑怎么处理跨根的链:
- 因为这题是求最值,不用考虑容斥,直接小合并(每次把一个小的子树合到已知的里面)。
- 当前子树和之前子树的集合合并:之前子树集合维护一个hash[i],到重心距离为i的边数最小值是hash[i]。
- 处理出当前子树所有点到重心的距离fi和经过的边se,如果fi == k 直接用se更新,否则找对应hash,hash[k - fi]中用他们的和更新。
- 计算距离时nowdis 大于k 直接return,既剪枝时间, 又使hash空间大小得到保证。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<int, int>
const int N = 2e5 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
int h[N], e[N << 1], w[N << 1], ne[N << 1], idx;
int gravity_max[N], gravity_size[N], gravity;
int sz; bool div_vis[N];
PII dis[N];int distot; int f[M]; int Clear[N], cnt_Clear;
int n, k; int ans = 0x3f3f3f3f;
void add ( int a, int b, int c ) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void get_gravity ( int u, int fa ) { //得到重心
gravity_size[u] = 1; gravity_max[u] = -1;
for ( int i = h[u]; ~i; i = ne[i] ) {
int v = e[i]; if(v == fa || div_vis[v]) continue;
get_gravity(v, u);
if(gravity_max[u] == -1 || gravity_max[u] < gravity_size[v]) {
gravity_max[u] = gravity_size[v];
}
gravity_size[u] += gravity_size[v];
}
gravity_max[u] = max(gravity_max[u], sz - gravity_size[u]);
if(gravity == -1 || gravity_max[gravity] > gravity_max[u]) gravity = u;
}
void get_size (int u, int fa) { //跑当前树大小
++ sz;
for ( int i = h[u]; ~i; i = ne[i] ) {
int v = e[i];
if ( v == fa || div_vis[v] ) continue;
get_size(v, u);
}
}
void get_dis(int u, int fa, ll nowdis, int cnt) { //每个点到u的距离算出来
if( nowdis > k) return; //剪枝,否则f要爆
dis[++ distot] = {nowdis, cnt};
for ( int i = h[u]; ~i; i = ne[i] ) {
int v = e[i]; if(v == fa || div_vis[v]) continue;
get_dis(v, u, nowdis + w[i], cnt + 1);
}
}
void tree_div ( int u ) {
sz = 0;
get_size(u, -1); //跑当前树大小
gravity = - 1;
get_gravity(u, -1); // 跑当前树重心
div_vis[gravity] = true; //去掉根节点,所有操作不再管gra
cnt_Clear = 0;
for ( int i = h[gravity]; ~i; i = ne[i] ) {
int v = e[i]; if( div_vis[v] ) continue;
distot = 0;
get_dis(v, gravity, w[i], 1);
for ( int j = 1; j <= distot; ++ j ) {
auto t = dis[j];
if(k - t.first > 0) ans = min(ans, f[k - t.first] + t.second);
else if(k - t.first == 0) ans = min(ans, t.second);
}
for ( int j = 1; j <= distot; ++ j ) {
auto t = dis[j];
f[t.first] = min(f[t.first], t.second);
Clear[++ cnt_Clear] = t.first;
}
}
for ( int i = 1; i <= cnt_Clear; ++ i ) {
f[Clear[i]] = INF;
}
for ( int i = h[gravity]; ~i; i = ne[i] ) { // 递归处理子树信息
int v = e[i]; if( div_vis[v] ) continue;
tree_div(v);
}
}
void init() {
memset(h, -1, sizeof h);
memset(div_vis, 0, sizeof div_vis);
memset(f, 0x3f, sizeof f); idx = 0;
}
int main () {
IOS
cin >> n >> k;
init(); int u, v, c;
for ( int i = 1; i < n; ++ i ) {
cin >> u >> v >> c; ++ u, ++ v;
add(u, v, c); add(v, u, c);
}
tree_div(1);
cout << (ans == INF ? "NAY" : "AYE") << '\n';
return 0;
}