HDU 4547 CD操作

传送门

没啥好说的。就是一个LCA。

不过就是有从根到子树里任意一个节点只需要一次操作,特判一下LCA是不是等于v。相等的话不用走。否则就是1次操作。

主要是想写一下倍增的板子。

倍增基于二进制。暴力求LCA算法是while循环一步一步往上走。但其实是不需要的。

因为一个点走到它的任意一个祖先都是确定的步数。都可用表示成二进制数。

$lca_{u,i}$代表从$u$向上走$2^{i}$步到哪一个节点

预处理出来。让$u$,$v$同深度,再向上走$x-1$步就好了($x$代表两$u, v$到它们LCA的深度差)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#include <iostream>
using namespace std;

inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    return x * f;
}
const int N = 1e5 + 10;
struct Edge { int v, next; } edge[N];
int n, m, cnt, head[N], fa[N], degree[N], lca[N][17], dep[N];
bool vis[N];
map<string, int> mp;
int tol;

inline void init() { 
    memset(head, 0, sizeof(head));
    memset(fa, 0, sizeof(fa));
    memset(vis, 0, sizeof(vis));
    memset(degree, 0, sizeof(degree));
    memset(lca, 0, sizeof(lca));
    cnt = tol = 0;
    mp.clear();
}

inline void addedge(int u, int v) {
    edge[++cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt;
}

int index(string s) {
    if (mp.find(s) != mp.end()) return mp[s];
    return mp[s] = ++tol; 
}

void dfs(int u) {
    vis[u] = 1;
    lca[u][0] = fa[u];
    for (int i = 1; i <= 16; i++) lca[u][i] = lca[lca[u][i-1]][i-1];
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].v;
        if (vis[v]) continue;
        dep[v] = dep[u] + 1;
        fa[v] = u;
        dfs(v); 
    }
}

int Lca(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    for (int i = 16; i >= 0; i--) if (dep[lca[u][i]] >= dep[v]) u = lca[u][i];
    if (u == v) return u;
    for (int i = 16; i >= 0; i--) if (lca[u][i] != lca[v][i]) u = lca[u][i], v = lca[v][i];
    return lca[u][0];
}

int main() {
    int T = read();
    while (T--) {
        init();
        n = read(); m = read();
        for (int i = 0; i < n - 1; i++) {
            string a, b;
            cin >> a >> b;
            int u = index(a), v = index(b);
            addedge(v, u);
            degree[u]++;
        }
        int root = 0;
        for (int i = 1; i <= n; i++) if (!degree[i]) { root = i; break; }
        fa[root] = root;
        dfs(root);
        while (m--) {
            string a, b;
            cin >> a >> b;
            int u = index(a), v = index(b);
            int r = Lca(u, v);
            printf("%d\n", dep[u] - dep[r] + (v == r ? 0 : 1));
        }
    }  
    return 0;
}
View Code

交了之后发现跑了两秒多

然后写了发tarjan的 跑了1秒多 果然 tarjan的时间复杂度还是最优的

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#include <iostream>
using namespace std;

inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
    return x * f;
}
const int N = 1e5 + 10;
struct Edge { int v, next; } edge[N];
int cnt, head[N];
inline void addedge(int u, int v) {
    edge[++cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt;
}
struct Qedge { int v, next, num; } qedge[N * 2];
int qcnt, qhead[N];
inline void addqedge(int u, int v, int num) {
    qedge[++qcnt].v = v;
    qedge[qcnt].next = qhead[u];
    qhead[u] = qcnt;
    qedge[qcnt].num = num;
}
int n, m, fa[N], degree[N], dep[N];
int ans[N];
bool vis[N];
map<string, int> mp;
int tol;

inline void init() { 
    memset(head, 0, sizeof(head));
    memset(qhead, 0, sizeof(qhead));
    memset(fa, 0, sizeof(fa));
    memset(vis, 0, sizeof(vis));
    memset(degree, 0, sizeof(degree));
    memset(dep, 0, sizeof(dep));
    memset(ans, 0, sizeof(ans));
    cnt = qcnt = tol = 0;
    mp.clear();
}

int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }

int index(string s) {
    if (mp.find(s) != mp.end()) return mp[s];
    return mp[s] = ++tol; 
}

void dfs(int u) {
    fa[u] = u;
    vis[u] = 1;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].v;
        if (vis[v]) continue;
        dep[v] = dep[u] + 1;
        dfs(v);
        fa[v] = u;
    }
    for (int i = qhead[u]; i; i = qedge[i].next) {
        int v = qedge[i].v;
        if (vis[v]) {
            ans[qedge[i].num] = getfa(v);
        }
    }
}

int main() {
    int T = read();
    while (T--) {
        init();
        n = read(); m = read();
        for (int i = 0; i < n - 1; i++) {
            string a, b;
            cin >> a >> b;
            int u = index(a), v = index(b);
            addedge(v, u);
            degree[u]++;
        }
        int root = 0;
        for (int i = 1; i <= n; i++) if (!degree[i]) { root = i; break; }
        for (int i = 1; i <= m; i++) {
            string a, b;
            cin >> a >> b;
            int u = index(a), v = index(b);
            addqedge(u, v, i);
            addqedge(v, u, i);
        }
        dep[root] = 0;
        dfs(root);
        for (int i = 1; i <= m; i++) {
            int u = qedge[2 * i].v, v = qedge[2 * i - 1].v;
            printf("%d\n", dep[u] - dep[ans[i]] + (ans[i] == v ? 0 : 1));
        }
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/10781335.html
cd