ZJOI2019 language

ZJOI2019 language

If the city \ (u, v \) to carry out trade, called \ (u \) can be reached

So all is not difficult to find a point to reach connectivity

If the path \ (s \ to t \) including the point \ (U \) , \ (S, T \) is the \ (U \) two very far point, \ (U \) of the spanning tree communication \ (u \) of all minimum spanning tree very far point

So, we need to think in advance sub-problem: given a number of points a tree, how to find minimum spanning tree size?

This should be a classic problem. It may take a little thought to build a virtual tree.

For convenience, we had extremely hard point far point 111, and finally to calculate their impact.

We give points according dfs \ mathrm {dfs} dfs sort order, one by one and then added to the list. Uuu added assumed that the current dot, the dots before adding SSS set point, minimum spanning tree is SSS TTT. Clearly, in order to make uuu and TTT connectivity, TTT just need to find the nearest point uuu put together just fine, a point that "the nearest point" and is the SSS uuu in the lca \ mathrm {lca} lca. If you mathrm {dfs} dfs sequence has a good feel for dfs \, in fact, a point called the SSS, is added to the list on a point vvv! Uuu contribution so-deplca Depu (U, V) \ mathrm DEP} { U - \ mathrm DEP {} {\ mathrm {} LCA (U ,, V)} Depu -deplca (U, V). Remember the hard spot 111 points, finally, all points lca dep Save \ mathrm {dep} _ {\ text {} {lca} of all points \ mathrm} lca dep all points.

The above period may be a bit around, it is strongly recommended to draw a diagram feel!

Violence does not seem to add a little easy to use, the best at this time of partition segment tree finally heavyweight debut.

It is still dfs \ mathrm {dfs} dfs ordinal index, segment tree leaf node of each tree original control tap or not selected, each node represents a minimum set point 111 after hard point interval period spanning Tree size, coexist next to each index point set minimum and maximum points. Similarly, pushup \ mathrm {pushup} pushup is to be subtracted deplca (U, V) \ mathrm DEP {} {\ mathrm {} LCA (U ,, V)} deplca (U, V). Uuu course at this time is left child of the selected index of the largest, vvv course, is the right child of the selected index minimal. As long as the query, then subtract all points with answers dep root of lca \ mathrm {dep} {\ text {all points} \ mathrm {lca}} dep lca to all points.

It sets a segment tree is not in vain more than log⁡ \ loglog it? Do not worry, positive solutions have surfaced.

Imagine each node has a tree line. Noting there is a path s → ts \ to ts → t, we will give each of them tree line on the path are selected on s, ts ,, ts, t two points. Routine according obtained lca = lca (u, v) \ mathrm {lca} = \ mathrm {lca} (u ,, v) lca = lca (u, v), equivalent to s → lca, t → lcas \ to \ mathrm {lca} ,, t \ to a \ mathrm {lca} s → lca, t → lca modified segment tree performs both chains. Still routine, modifying the chain may be converted into a differential tree marking, s, t, lca, fa [lca] s ,, t ,, \ mathrm {lca} ,, \ mathrm {fa} [\ mathrm {lca} ] s, t, lca, fa [lca] are marked 1,1, -1, -11, 1 ,, - ,, 1 - 11, 1, -1, -1.

Wait ...... tree line marking is possible, but each node should inherit his father's own information, how to do this?
Dynamic prescription + segment tree merge!

At this point, [ZJOI2019] almost finished practice the language. nnn times combined segment tree is O (nlog⁡n) O (n \ log n) O (nlogn) , and the revision claim nnn \ log nnlogn times lca \ mathrm {lca} lca, or if the multiplication tree sectional nlog⁡nn complexity is O (nlog⁡2n) O (n \ log ^ 2 n) O (nlog2n), if the Euler sequence st \ mathrm {st} st table, a beautiful complexity O (nlog⁡n) O (n \ log n) O ( nlogn).
Code

Just ask the (u, v) (u ,, v) (u, v) is not mandatory u <vu <vu <v, the answer is divided by 222.

#include <cmath>
#include <cstdio>
#include <vector>
#include <algorithm>

const int N = 200005, V = 6400005, L = 18;

int n, m, tms, o[N], ft[N], dep[N], dfn[N], st[L][N];
std::vector<int> to[N], del[N];
long long ans;

inline int getLca(int u, int v);

struct SegmentTree {
    int tot, c[V], f[V], s[V], t[V], ls[V], rs[V], rt[N];

    inline void pushUp(int u) {
        f[u] = f[ls[u]] + f[rs[u]] - dep[getLca(t[ls[u]], s[rs[u]])];
        s[u] = s[ls[u]] ? s[ls[u]] : s[rs[u]];
        t[u] = t[rs[u]] ? t[rs[u]] : t[ls[u]];
    }
    inline int query(int u) { return f[u] - dep[getLca(s[u], t[u])]; }
    void modify(int &u, int l, int r, int p, int x) {
        if (!u) { u = ++tot; }
        if (l == r) {
            c[u] += x; f[u] = c[u] ? dep[p] : 0; s[u] = t[u] = c[u] ? p : 0;
            return;
        }
        int mid = l + r >> 1;
        if (dfn[p] <= mid) { modify(ls[u], l, mid, p, x); }
        else { modify(rs[u], mid + 1, r, p, x); }
        pushUp(u);
    }
    void merge(int &u, int v, int l, int r) {
        if (!u || !v) { u |= v; return; }
        if (l == r) {
            c[u] += c[v]; f[u] |= f[v]; s[u] |= s[v]; t[u] |= t[v];
            return;
        }
        int mid = l + r >> 1;
        merge(ls[u], ls[v], l, mid); merge(rs[u], rs[v], mid + 1, r); pushUp(u);
    }
} smt;

void build() {
    for (int i = 1; i <= tms; i++) { o[i] = log(i) / log(2) + 1e-7; }
    for (int i = 1; i <= o[tms]; i++) {
        for (int j = 1, u, v; j + (1 << i) - 1 <= tms; j++) {
            u = st[i - 1][j]; v = st[i - 1][j + (1 << i - 1)];
            st[i][j] = dep[u] < dep[v] ? u : v;
        }
    }
}
inline int getLca(int u, int v) {
    if (!u || !v) { return 0; } u = dfn[u]; v = dfn[v];
    if (u > v) { std::swap(u, v); }
    int d = o[v - u + 1]; u = st[d][u]; v = st[d][v - (1 << d) + 1];
    return dep[u] < dep[v] ? u : v;
}

void dfs(int u, int fa) {
    ft[u] = fa; dep[u] = dep[fa] + 1; st[0][++tms] = u; dfn[u] = tms;
    for (auto v : to[u]) { if (v != fa) { dfs(v, u); st[0][++tms] = u; } }
}
void solve(int u) {
    for (auto v : to[u]) { if (v != ft[u]) { solve(v); } }
    for (auto v : del[u]) { smt.modify(smt.rt[u], 1, tms, v, -1); }
    ans += smt.query(smt.rt[u]); smt.merge(smt.rt[ft[u]], smt.rt[u], 1, tms);
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 2, u, v; i <= n; i++) {
        scanf("%d%d", &u, &v);
        to[u].push_back(v); to[v].push_back(u);
    }
    dfs(1, 0); build();
    for (int u, v, lca; m; m--) {
        scanf("%d%d", &u, &v); lca = getLca(u, v);
        smt.modify(smt.rt[u], 1, tms, u, 1); smt.modify(smt.rt[u], 1, tms, v, 1);
        smt.modify(smt.rt[v], 1, tms, u, 1); smt.modify(smt.rt[v], 1, tms, v, 1);
        del[lca].push_back(u); del[ft[lca]].push_back(u);
        del[lca].push_back(v); del[ft[lca]].push_back(v);
    }
    solve(1); printf("%lld\n", ans >> 1);
    return 0;
}

Guess you like

Origin www.cnblogs.com/wawawa8/p/11094612.html