洛谷上的lca模板题——传送门
学了求lca的tarjan算法(离线),在洛谷上做模板题,结果后三个点超时。
又把询问改成链式前向星,才ok。
这个博客,tarjan分析的很详细。
附代码——
#include <cstdio> #include <cstring> const int maxn = 500001; int n, m, cnt, s, cns; int x, y, z[maxn];//z是x和y的lca int f[maxn], head[maxn], from[maxn]; bool vis[maxn]; struct node { int to, next; }e[2 * maxn]; struct Node { int to, next, num; }q[2 * maxn]; 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 - '0'; ch = getchar(); } return x * f; } inline void ask(int u, int v, int i)//储存待询问的结构体,也是链式前向星优化 { q[cns].num = i;//num表示第几次询问 q[cns].to = v; q[cns].next = from[u]; from[u] = cns++; } inline void add(int u, int v)// { e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++; } inline int find(int a) { return a == f[a] ? a : f[a] = find(f[a]);//路径压缩优化 } /*inline void Union(int a, int b) { int fx = find(a), fy = find(b); if(fx == fy) return; f[fy] = fx; }*/ inline void tarjan(int k) { int i, j; vis[k] = 1; f[k] = k; for(i = head[k]; i != -1; i = e[i].next) if(!vis[e[i].to]) { tarjan(e[i].to); //Union(k, e[i].to); f[e[i].to] = k; } for(i = from[k]; i != -1; i = q[i].next) if(vis[q[i].to] == 1) z[q[i].num] = find(q[i].to); } int main() { int i, j, u, v; n = read(); m = read(); s = read(); memset(head, -1, sizeof(head)); memset(from, -1, sizeof(from)); for(i = 1; i <= n - 1; i++) { u = read(); v = read(); add(u, v);//注意添加两遍 add(v, u); } for(i = 1; i <= m; i++) { x = read(); y = read(); ask(x, y, i);//两遍 ask(y, x, i); } tarjan(s); for(i = 1; i <= m; i++) printf("%d\n", z[i]); return 0; }