JZOJ3225[BJOI2013]load(圓方樹+樹鏈剖分/樹上差分)

題目連接

JZOJ3225ios

題目大意

給出一張\(N\)個點\(M\)條邊的無向圖,和\(Q\)對點對\(p_i, q_i\),問最後圖中每一個點一定被\(p_i\)\(q_i\)的路徑覆蓋多少次ui

\(N \le 1e5, M, Q \le 2e5\)spa

樣例輸入 樣例輸出
4 4 2
1 2
1 3
2 3
1 4
4 2
4 3
2
1
1
2

解析

考慮\(p\)\(q\)的路徑一定通過哪些點,顯然是\(p\)\(q\)的簡單路徑通過的割點.net

回憶圓方樹的構造,樹上度數大於\(1\)的圓點就是原圖上的割點code

那麼問題就簡單了,建出圓方樹,而後\(p\)\(q\)路徑上的圓點答案都會加\(1\)(由於題目提及點和終點也算,就不用特殊處理了)get

我拿了個樹剖來維護,也能夠樹上差分string

代碼

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#define MAXN 100005

typedef long long LL;
struct Graph {
    struct Edge {
        int v, next;
        Edge(int _v = 0, int _n = 0):v(_v), next(_n) {}
    } edge[MAXN << 2];
    int head[MAXN << 1], cnt;
    void init() { memset(head, -1, sizeof head); cnt = 0; }
    void add_edge(int u, int v) { edge[cnt] = Edge(v, head[u]); head[u] = cnt++; }
    void insert(int u, int v) { add_edge(u, v); add_edge(v, u); }
};
struct SegmentTree {
    int add[MAXN << 3];
    void update(int, int, int, int, int);
    int query(int, int, int, int);
};

char gc();
int read();
void Tarjan(int, int);
void rebuild();
void dfs1(int);
void dfs2(int);

int N, M, Q, idx, tot;
int dfn[MAXN << 1], top[MAXN << 1], fa[MAXN << 1], dep[MAXN << 1], low[MAXN], size[MAXN << 1], heavy[MAXN << 1];
int stk[MAXN], stop;
std::vector<int> bel[MAXN];
Graph G;
SegmentTree sgt;

int main() {
    G.init();
    tot = N = read(), M = read(), Q = read();
    for (int i = 1; i <= M; ++i) G.insert(read(), read());
    Tarjan(1, 0);
    rebuild();
    dfs1(1);
    top[1] = 1, idx = 0;
    dfs2(1);
    while (Q--) {
        int p = read(), q = read();
        while (top[p] ^ top[q]) {
            if (dep[top[p]] < dep[top[q]]) std::swap(p, q);
            sgt.update(1, 1, tot, dfn[top[p]], dfn[p]);
            p = fa[top[p]];
        }
        if (dep[p] > dep[q]) std::swap(p, q);
        sgt.update(1, 1, tot, dfn[p], dfn[q]);
    }
    for (int i = 1; i <= N; ++i)
        printf("%d\n", sgt.query(1, 1, tot, dfn[i]));

    return 0;
}
inline char gc() {
    static char buf[1000000], *p1, *p2;
    if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
    return p1 == p2 ? EOF : *p2++;
}
inline int read() {
    int res = 0; char ch = gc();
    while (ch < '0' || ch > '9') ch = gc();
    while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc();
    return res;
}
void SegmentTree::update(int rt, int L, int R, int l, int r) {
    if (L >= l && R <= r) ++add[rt];
    else {
        int mid = (L + R) >> 1;
        if (l <= mid) update(rt << 1, L, mid, l, r);
        if (r > mid) update(rt << 1 | 1, mid + 1, R, l, r);
    }
}
int SegmentTree::query(int rt, int L, int R, int pos) {
    if (L == R) return add[rt];
    int mid = (L + R) >> 1;
    if (pos <= mid) return add[rt] + query(rt << 1, L, mid, pos);
    else return add[rt] + query(rt << 1 | 1, mid + 1, R, pos);
}
void Tarjan(int u, int fa) {
    dfn[u] = low[u] = ++idx;
    for (int i = G.head[u]; ~i; i = G.edge[i].next) {
        int v = G.edge[i].v;
        if (v == fa) continue;
        if (!dfn[v]) {
            stk[stop++] = v;
            Tarjan(v, u);
            low[u] = std::min(low[u], low[v]);
            if (low[v] >= dfn[u]) {
                int p; ++tot;
                do {
                    p = stk[--stop];
                    bel[p].push_back(tot);
                } while (p ^ v);
                bel[u].push_back(tot);
            }
        } else low[u] = std::min(low[u], dfn[v]);
    }
}
void rebuild() {
    G.init();
    for (int i = 1; i <= N; ++i) for (int j = 0; j < bel[i].size(); ++j)
        G.insert(i, bel[i][j]);
}
void dfs1(int u) {
    dep[u] = dep[fa[u]] + 1;
    size[u] = 1;
    for (int i = G.head[u]; ~i; i = G.edge[i].next) {
        int v = G.edge[i].v;
        if (v == fa[u]) continue;
        fa[v] = u, dfs1(v);
        size[u] += size[v];
        if (!heavy[u] || size[heavy[u]] < size[v]) heavy[u] = v;
    }
}
void dfs2(int u) {
    dfn[u] = ++idx;
    if (heavy[u]) {
        top[heavy[u]] = top[u];
        dfs2(heavy[u]);
    }
    for (int i = G.head[u]; ~i; i = G.edge[i].next) {
        int v = G.edge[i].v;
        if (v == fa[u] || v == heavy[u]) continue;
        top[v] = v, dfs2(v);
    }
}
//Rhein_E
相關文章
相關標籤/搜索