靜態點分治

9102700發表於2024-06-06

這不就是樹上的二分嗎!!!

樹的重心:以節點 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;
}

相關文章