HDU6200 mustedge mustedge mustedge (2017 ACM/ICPC Asia Regional Shenyang Online)

传送门

题目大意

给出一张连通图,现在有两种操作:
1 u v :向图中加入一条连接 u v 的边
2 u v :询问 u v 之间的必经边的条数

思路

首先随便找到一个生成树,每条边的初始权值为1,对于所有非树边 (u,v) ,将生成树上 u v 的路径上的所有边的权值都变为0,那么询问时只需要回答 u v 的边权和即可,这就很容易了。
然后考虑加边操作,因为每一条边只会被删除一次,所以我们可以记录每一个节点在它到根的路径上离它最近的一个没有被删除的边,通过并查集维护。

代码

#include 
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, q, t[MAXN], f[MAXN], fa[MAXN], adj[MAXN], c, out[MAXN], dfn[MAXN];
int edge[MAXN][2], dcnt, sz[MAXN], hsn[MAXN], htp[MAXN], dep[MAXN];
struct { int v, nxt; } e[MAXN << 1];
inline void Addedge(int u, int v) {
    e[++ c].v = v; e[c].nxt = adj[u]; adj[u] = c;
}
inline void GET(int&n) {
    static char c; n = 0;
    do c = getchar(); while('0' > c || c > '9');
    while('0' <= c && c <= '9') { n = n * 10 + c - '0'; c = getchar(); }
}
inline void Add(int x, int v) {
    for(; x <= n; x += x&-x) t[x] += v;
}
inline int Qsum(int x) {
    int ans = 0;
    for(; x > 0; x -= x&-x) ans += t[x];
    return ans;
}
int Find(int x) { return (x == f[x]) ? x : (f[x] = Find(f[x])); }
void dfs(int u) {
    dep[u] = dep[fa[u]] + 1; dfn[u] = ++ dcnt; sz[u] = 1; hsn[u] = 0;
    for(int i = adj[u]; i; i = e[i].nxt) if(e[i].v != fa[u]) {
        fa[e[i].v] = u;
        dfs(e[i].v); sz[u] += sz[e[i].v];
        if(sz[e[i].v] > sz[hsn[u]]) hsn[u] = e[i].v;
    }
    out[u] = dcnt;
}
void dfs2(int u, int tp) {
    htp[u] = tp;
    if(hsn[u]) dfs2(hsn[u], tp);
    for(int i = adj[u]; i ; i = e[i].nxt)
        if(e[i].v != fa[u] && e[i].v != hsn[u])
            dfs2(e[i].v, e[i].v);
}
int LCA(int u, int v) {
    while(htp[u] != htp[v]) {
        if(dep[htp[u]] < dep[htp[v]]) swap(u, v);
        u = fa[htp[u]];
    }
    return dep[u] < dep[v] ? u : v;
}
void Adde(int u, int v) {   //to add not_in_tree edge
    int lca = LCA(u, v), a = u, b = v, x;
    for(; dep[(x = Find(a))] > dep[lca]; a = fa[x]) {
        Add(dfn[x], -1); Add(out[x]+1, 1); f[x] = Find(fa[x]);
    }
    for(; dep[(x = Find(b))] > dep[lca]; b = fa[x]) {
        Add(dfn[x], -1); Add(out[x]+1, 1); f[x] = Find(fa[x]);
    }
}
int Query(int u) {
    return dep[u] + Qsum(dfn[u]);
}
int main() {
    int T, u, v, cnt, op; cin >> T;
    for(int Cas = 1; Cas <= T; ++ Cas) {
        cin >> n >> m; cnt = dcnt = c = 0;
        for(int i = 1; i <= n; ++ i) f[i] = i, adj[i] = 0, t[i] = 0;
        for(int i = 1; i <= m; ++ i) {
            GET(u); GET(v);
            if(Find(u) != Find(v)) {
                Addedge(u, v);
                Addedge(v, u);
                f[Find(u)] = Find(v);
            } else {
                edge[++ cnt][0] = u;
                edge[cnt][1] = v;
            }
        }
        fa[1] = 0;
        dfs(1); dfs2(1, 1);
        for(int i = 1; i <= n; ++ i) f[i] = i;
        for(int i = 1; i <= cnt; ++ i)
            Adde(edge[i][0], edge[i][1]);
        scanf("%d", &q);
        printf("Case #%d:\n", Cas);
        for(int i = 1; i <= q; ++ i) {
            GET(op); GET(u); GET(v);
            if(op == 1) Adde(u, v);
            else printf("%d\n", Query(u) + Query(v) - 2 * Query(LCA(u, v)));
        }
    }
    return 0;
}

你可能感兴趣的:(图论)