POJ 1470 Closest Common Ancestors(LCA&RMQ)
题意比较费劲:输入看起来很麻烦。处理括号冒号的时候是用%1s就可以。还有就是注意它有根节点。。。Q次查询
在线st算法
/************************************************************************* > File Name: 3.cpp > Author: Howe_Young > Mail: 1013410795@qq.com > Created Time: 2015年10月08日 星期四 19时03分30秒 ************************************************************************/ #include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 10000; struct Edge { int to, next; }edge[maxn<<1]; int tot, head[maxn]; int ans[maxn]; int Euler[maxn<<1]; int R[maxn]; int dep[maxn]; int dp[maxn<<1][20]; // RMQ bool in[maxn]; int cnt; void init() { cnt = 0; tot = 0; memset(head, -1, sizeof(head)); memset(ans, 0, sizeof(ans)); memset(in, false, sizeof(in)); } void addedge(int u, int v) { edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } void dfs(int u, int depth) { Euler[++cnt] = u; R[u] = cnt; dep[cnt] = depth; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; dfs(v, depth + 1); Euler[++cnt] = u; dep[cnt] = depth; } } void RMQ(int n) { for (int i = 1; i <= n; i++) dp[i][0] = i; int m = (int)(log(n) / log(2)); for (int j = 1; j <= m; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i++) dp[i][j] = dep[dp[i][j - 1]] < dep[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]; } } int query(int u, int v) { int l = R[u], r = R[v]; if (l > r) swap(l, r); int k = (int)(log(r - l + 1) / log(2)); int lca = dep[dp[l][k]] < dep[dp[r - (1 << k) + 1][k]] ? dp[l][k] : dp[r - (1 << k) + 1][k]; return Euler[lca]; } int main() { int n; while (~scanf("%d", &n)) { init(); char s1[3], s2[3]; int u, v, m; for (int i = 0; i < n; i++) { scanf("%d %1s %1s %d %1s", &u, s1, s1, &m, s2); for (int j = 0; j < m; j++) { scanf("%d", &v); addedge(u, v); in[v] = true; } } for (int i = 1; i <= n; i++) if (!in[i]) { dfs(i, 1); break; } RMQ(cnt); int Q; scanf("%d", &Q); while (Q--) { scanf("%1s %d %d %1s", s1, &u, &v, s2); ans[query(u, v)]++; } for (int i = 1; i <= n; i++) if (ans[i]) printf("%d:%d\n", i, ans[i]); } return 0; }
离线tarjan算法:
#include <cstdio> #include <cstring> using namespace std; const int maxn = 1000;//节点 const int maxm = 1000010;//最大查询数 struct Edge { int to, next; }edge[maxn * 2]; int tot, head[maxn]; struct Query { int q, next; int index; }query[maxm * 2]; int cnt, h[maxn]; int fa[maxn]; int r[maxn]; int ancestor[maxn]; int ans[maxm]; int Q; bool vis[maxn]; void init(int n) { Q = 0; tot = 0; cnt = 0; memset(head, -1, sizeof(head)); memset(h, -1, sizeof(h)); memset(fa, -1, sizeof(fa)); memset(ancestor, 0, sizeof(ancestor)); memset(vis, false, sizeof(vis)); for (int i = 1; i <= n; i++) r[i] = 1; } void addedge(int u, int v) { edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } void addquery(int u, int v, int index) { query[cnt].q = v; query[cnt].index = index; query[cnt].next = h[u]; h[u] = cnt++; } int find(int x) { if (fa[x] == -1) return x; return fa[x] = find(fa[x]); } void Union(int x, int y) { int tx = find(x); int ty = find(y); if (tx != ty) { if (tx < ty) { fa[tx] = ty; r[ty] += r[tx]; } else { fa[ty] = tx; r[tx] += r[ty]; } } } void LCA(int u) { vis[u] = true; ancestor[u] = u; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (vis[v]) continue; LCA(v); Union(u, v); ancestor[find(u)] = u; } for (int i = h[u]; i != -1; i = query[i].next) { int v = query[i].q; if (vis[v]) { ans[query[i].index] = ancestor[find(v)]; } } } int res[maxn]; bool in[maxn]; int main() { int n; while (~scanf("%d", &n)) { init(n); memset(in, false, sizeof(in)); int u, v, m; char ch[2]; for (int i = 1; i <= n; i++) { scanf("%d %1s %1s %d %1s", &u, ch, ch, &m, ch); for (int j = 0; j < m; j++) { scanf("%d", &v); in[v] = true; addedge(u, v); addedge(v, u); } } int q; scanf("%d", &q); while (q--) { scanf("%1s %d %d %1s", ch, &u, &v, ch); addquery(u, v, Q); addquery(v, u, Q++); } int root; for (int i = 1; i <= n; i++) { if (!in[i]) { root = i; break; } } LCA(root); memset(res, 0, sizeof(res)); for (int i = 0; i < Q; i++) res[ans[i]]++; for (int i = 1; i <= n; i++) if (res[i]) printf("%d:%d\n", i, res[i]); } return 0; }