点分治入门学习笔记

模板链接 \(Click\) \(Here\)

终于又打开了一个天坑。。。。点分治真的是好东西呢\(QwQ\)

点分治的核心思想在于把问题划分为每一个点可以统计的形式,然后对树上的点进行分治。为了保证复杂度为\(log\),需要每次都找询问子树的重心。

可以很好的解决关于所有链信息的询问。通常离线。

#include <bits/stdc++.h>
using namespace std;

const int M = 110;
const int N = 10010;
const int INF = 10000010;

int n, m, cnt, head[N];

struct edge {
    int nxt, to, w;

    edge (int _nxt = 0, int _to = 0, int _w = 0) {
        nxt = _nxt, to = _to, w = _w;
    }
    
}e[N << 1];

void add_len (int u, int v, int w) {
    e[++cnt] = edge (head[u], v, w); head[u] = cnt;
    e[++cnt] = edge (head[v], u, w); head[v] = cnt;
}

int rt, sum, sz[N], qry[M], rem[N], res[M], dis[N], maxp[N];

bool vis[N], have[INF];

void get_root (int u, int fa) {
    sz[u] = 1, maxp[u] = 0;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v != fa && !vis[v]) { //vis 限制只访问这棵子树的信息。
            get_root (v, u);
            sz[u] += sz[v];
            maxp[u] = max (maxp[u], sz[v]);
        }
    }
    maxp[u] = max (maxp[u], sum - sz[u]); //sum 是当前子树大小
    if (maxp[u] < maxp[rt]) rt = u;
}

void get_dis (int u, int fa) {
    rem[++rem[0]] = dis[u];
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (!vis[v] && v != fa) {
            dis[v] = dis[u] + e[i].w;
            get_dis (v, u);
        }
    }
}

queue <int> q;

void calc (int u) {
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (!vis[v]) {
            rem[0] = 0, dis[v] = e[i].w;
            get_dis (v, u);
            for (int j = 1; j <= rem[0]; ++j) {
                for (int k = 1; k <= m; ++k) {
                    if (qry[k] >= rem[j]) {
                        res[k] |= have[qry[k] - rem[j]];
                    }
                }
            }
            for (int j = 1; j <= rem[0]; ++j) {
                q.push (rem[j]); have[rem[j]] = true;
            }
        }
    }
    while (!q.empty ()) have[q.front ()] = false, q.pop ();
}

void solve (int u) {
    //have[i] -> 是否存在 dis = i 的路径
    vis[u] = have[0] = true; calc (u);
    //只能访问 u 的子树, 计算 u 子树的状态
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (!vis[v]) {
            sum = sz[v];
            maxp[rt = 0] = INF;
            get_root (v, 0);
            solve (rt);
        }
    }
}

int main () {
    cin >> n >> m;
    for (int i = 1; i <= n - 1; ++i) {
        static int u, v, w;
        cin >> u >> v >> w;
        add_len (u, v, w);
    }
    for (int i = 1; i <= m; ++i) cin >> qry[i];
    maxp[rt] = sum = n;
    get_root (1, 0);
    solve (rt);
    for (int i = 1; i <= m; ++i) {
        puts (res[i] ? "AYE" : "NAY");
    }
} 

猜你喜欢

转载自www.cnblogs.com/maomao9173/p/10515652.html
今日推荐