這不就是樹上的二分嗎!!!
樹的重心:以節點 u 為根, 節點 u 的最大子樹節點數最少
分別講述四個重要函式
1.找出重心:getroot()
int del[N], siz[N], mxs, sum, root; // 求根
void getroot(int u, int father){
siz[u] = 1;
int s = 0;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v] || v == father) continue;
getroot(v, u);
siz[u] += siz[v];
s = max(s, siz[v]);
}
s = max(s, sum - siz[u]);
if(s < mxs) mxs = s, root = u;
}
2.找出到根的距離 getdis()
ll dis[N], d[N];
int vcnt;
void getdis(int u, int father){
dis[++vcnt] = d[u];
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v] || v == father) continue;
d[v] = d[u] + e[i].val;
getdis(v, u);
}
}
3.對當前的樹統計答案 calc() -- 最重要,不同題目就改變這個
int ans[N], q[Num], judge[Num];
void calc(int u){
del[u] = judge[0] = 1;
int p = 0;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v]) continue;
vcnt = 0;
d[v] = e[i].val;
getdis(v, u);
for(int j = 1; j <= vcnt; j++){
for(int k = 1; k <= m; k++){
if(ask[k] >= dis[j]){
ans[k] |= judge[ask[k] - dis[j]];
}
}
}
for(int j = 1; j <= vcnt; j++){
if(dis[j] < inf) q[++p] = dis[j], judge[dis[j]] = 1;
}
}
for(int i = 1; i <= p; i++) judge[q[i]] = 0;
}
4.分治,呼叫以上函式 divide()
void divide(int u){
calc(u);
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v]) continue;
mxs = sum = siz[v];
getroot(v, 0);
divide(root);
}
}
模板題連結
下面是完整程式碼
點選檢視程式碼
// Created by qyy on 2024/6/5.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define PII pair<int, int>
#define endl "\n"
const long long inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
const int Num = 1e7 + 10;
const int mod = 1e9 + 7;
int n, m, ask[N];
int head[N], cnt;
struct Edge{
int from, to, nxt;
ll val;
}e[N << 1];
void add(int u, int v, ll val){
e[++cnt].from = u;
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
e[cnt].val = val;
}
int del[N], siz[N], mxs, sum, root; // 求根
void getroot(int u, int father){
siz[u] = 1;
int s = 0;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v] || v == father) continue;
getroot(v, u);
siz[u] += siz[v];
s = max(s, siz[v]);
}
s = max(s, sum - siz[u]);
if(s < mxs) mxs = s, root = u;
}
ll dis[N], d[N];
int vcnt;
void getdis(int u, int father){
dis[++vcnt] = d[u];
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v] || v == father) continue;
d[v] = d[u] + e[i].val;
getdis(v, u);
}
}
int ans[N], q[Num], judge[Num];
void calc(int u){
del[u] = judge[0] = 1;
int p = 0;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v]) continue;
vcnt = 0;
d[v] = e[i].val;
getdis(v, u);
for(int j = 1; j <= vcnt; j++){
for(int k = 1; k <= m; k++){
if(ask[k] >= dis[j]){
ans[k] |= judge[ask[k] - dis[j]];
}
}
}
for(int j = 1; j <= vcnt; j++){
if(dis[j] < inf) q[++p] = dis[j], judge[dis[j]] = 1;
}
}
for(int i = 1; i <= p; i++) judge[q[i]] = 0;
}
void divide(int u){
calc(u);
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(del[v]) continue;
mxs = sum = siz[v];
getroot(v, 0);
divide(root);
}
}
void solve() {
cin >> n >> m;
for(int i = 1; i < n; i++){
int u, v;
ll val;
cin >> u >> v >> val;
add(u, v, val);
add(v, u, val);
}
for(int i = 1; i <= m; i++) cin >> ask[i];
mxs = sum = n;
getroot(1, 0);
divide(root);
for(int i = 1; i <= m; i++){
if(ans[i]) cout << "AYE\n";
else cout << "NAY\n";
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
//cin >> t;
while (t--) {
solve();
}
return 0;
}