静态点分治
这不就是树上的二分吗!!!
树的重心:以节点 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;
}

浙公网安备 33010602011771号