「BZOJ 3365」Distance Statistics - 点分治

约翰提供一个整数 ),希望你输出有多少对农场之间的距离是不超过 的。

链接

BZOJ 3365

题解

BZOJ 1468 一样。

代码

#include <algorithm>
#include <stack>
#include <queue>
#include <vector>

const int MAXN = 40000;

struct Node;
struct Edge;

struct Node {
    Edge *e;
    bool solved, visited;
    int size, dist, max;
    Node *parent;
} N[MAXN];

struct Edge {
    Node *s, *t;
    int w;
    Edge *next;

    Edge(Node *s, Node *t, const int w) : s(s), t(t), w(w), next(s->e) {}
};

inline void addEdge(const int s, const int t, const int w) {
    N[s].e = new Edge(&N[s], &N[t], w);
    N[t].e = new Edge(&N[t], &N[s], w);
}

int n, k;
// int cnt_root, cnt_calc;

inline Node *center(Node *start) {
    std::stack<Node *> s;
    s.push(start);
    start->visited = false;
    start->parent = NULL;

    static Node *a[MAXN];
    int cnt = 0;
    while (!s.empty()) {
        Node *v = s.top();
        if (!v->visited) {
            a[cnt++] = v;
            v->visited = true;
            for (Edge *e = v->e; e; e = e->next) if (e->t != v->parent && !e->t->solved) {
                e->t->parent = v;
                e->t->visited = false;
                s.push(e->t);
            }
        } else {
            v->size = 1;
            v->max = 0;
            for (Edge *e = v->e; e; e = e->next) if (!e->t->solved && e->t->parent == v) {
                v->size += e->t->size;
                v->max = std::max(v->max, e->t->size);
            }
            s.pop();
        }
    }

    // printf("start->size - cnt = %d\n", start->size - cnt);
    Node *res = NULL;
    for (int i = 0; i < cnt; i++) {
        a[i]->max = std::max(a[i]->max, start->size - a[i]->max);
        if (!res || res->max > a[i]->max) res = a[i];
    }

    // printf("root(%ld) = %ld\n", start - N + 1, res - N + 1);
    // cnt_root++;
    return res;
}

inline int calc(Node *root, const int dist = 0) {
    static int a[MAXN];
    int cnt = 0;

    std::queue<Node *> q;
    q.push(root);
    root->dist = dist;
    root->parent = NULL;
    while (!q.empty()) {
        Node *v = q.front();
        q.pop();

        a[cnt++] = v->dist;

        for (Edge *e = v->e; e; e = e->next) if (!e->t->solved && e->t != v->parent) {
            e->t->parent = v;
            e->t->dist = v->dist + e->w;
            q.push(e->t);
        }
    }

    int res = 0;
    std::sort(a, a + cnt);
    for (int i = 0, j = cnt - 1; i < j; i++) {
        while (i < j && a[i] + a[j] > k) j--;
        res += j - i;
    }

    // cnt_calc++;

    return res;
}

inline int solve() {
    std::stack<Node *> s;
    s.push(&N[0]);

    int ans = 0;
    while (!s.empty()) {
        Node *v = s.top();
        s.pop();
        // printf("work(%ld)\n", v - N + 1);

        Node *root = center(v);
        root->solved = true;

        ans += calc(root);
        for (Edge *e = root->e; e; e = e->next) if (!e->t->solved) {
            ans -= calc(e->t, e->w);
            s.push(e->t);
        }
    }

    return ans;
}

int main() {
    int m;
    scanf("%d %d", &n, &m);

    for (int i = 0; i < n - 1; i++) {
        int u, v, w;
        char s[2];
        scanf("%d %d %d %s", &u, &v, &w, s), u--, v--;
        addEdge(u, v, w);
    }

    scanf("%d", &k);

    int ans = solve();
    printf("%d\n", ans);
    // printf("cnt_root = %d, cnt_calc = %d\n", cnt_root, cnt_calc);

    return 0;
}