luoguP4320 道路相遇 圆方树

标题已经告诉你怎么做了.....

两点间的圆点个数即为所求

建出圆方树后打个树剖求$lca$就行.....

复杂度$O(n + q \log n)$

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

extern inline char gc() {
    static char RR[23456], *S = RR + 23333, *T = RR + 23333;
    if(S == T) fread(RR, 1, 23333, stdin), S = RR;
    return *S ++;
}
inline int read() {
    int p = 0, w = 1; char c = gc();
    while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
    while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
    return p * w;
}

int wr[50], rw;
#define pc(o) *O ++ = o
char WR[40000005], *O = WR;
inline void write(int x) {
    if(!x) pc('0');
    if(x < 0) pc('-'), x = -x;
    while(x) wr[++ rw] = x % 10, x /= 10;
    while(rw) pc(wr[rw --] + '0'); pc('\n');
}

#define ri register int
#define sid 500050
#define nid 1005000
#define eid 4005000

int n, m, cnp;
int cap[sid], aap[nid], nxt[eid], node[eid]; 

inline void cop(int u, int v) { nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v; }
inline void bop(int u, int v) { nxt[++ cnp] = aap[u]; aap[u] = cnp; node[cnp] = v; }

int st[sid], snp, scc;
int dfn[sid], low[sid], dfn_id;

#define cur node[i]

void tarjan(int o) {
    st[++ snp] = o;
    dfn[o] = low[o] = ++ dfn_id;
    for(int i = cap[o]; i; i = nxt[i])
    if(!dfn[cur]) {
        tarjan(cur); low[o] = min(low[o], low[cur]);
        if(low[cur] < dfn[o]) continue;
        int e; ++ scc; bop(o, scc);
        do { e = st[snp --]; bop(scc, e); } while(e != cur);
    }
    else low[o] = min(low[o], dfn[cur]);
}

int anc[nid], fa[nid], sz[nid];
int dep[nid], de[nid], son[nid];

void dfs(int o) {
    sz[o] = 1; de[o] = de[fa[o]] + (o <= n);
    for(int i = aap[o]; i; i = nxt[i])
    if(cur != fa[o]) {
        dep[cur] = dep[o] + 1; fa[cur] = o; 
        dfs(cur); sz[o] += sz[cur];
        if(sz[son[o]] < sz[cur]) son[o] = cur;
    }
}

void dfs(int o, int tp) {
    anc[o] = tp; if(!son[o]) return; dfs(son[o], tp);
    for(int i = aap[o]; i; i = nxt[i])
    if(cur != fa[o] && cur != son[o]) dfs(cur, cur);
}

int lca(int u, int v) {
    int pu = anc[u], pv = anc[v];
    while(pu != pv) {
        if(dep[pu] < dep[pv]) swap(u, v), swap(pu, pv);
        u = fa[pu]; pu = anc[u];
    } 
    return (dep[u] < dep[v]) ? u : v;
}

int main() {
    scc = n = read(); m = read();
    for(ri i = 1; i <= m; i ++) {
        int u = read(), v = read();
        cop(u, v); cop(v, u);
    }
    tarjan(1); dfs(1); dfs(1, 1);
    int q = read();
    for(ri i = 1; i <= q; i ++) {
        int u = read(), v = read(), o = lca(u, v);
        write(de[u] + de[v] - de[o] - de[fa[o]]);
    }
    fwrite(WR, 1, O - WR, stdout);
    return 0;
}

 

posted @ 2018-08-22 23:21  remoon  阅读(238)  评论(0编辑  收藏  举报