pku Nearest Common Ancestors LCA 问题(rmq && tarjan)解决
http://poj.org/problem?id=1330
题意:给n个点,n-1条边,一棵树,求每个询问的LCA;
思路:
rmq求LCA。。。。http://dongxicheng.org/structure/lca-rmq/
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll __int64 #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 100007 #define N 10007 using namespace std; //freopen("din.txt","r",stdin); struct node{ int v; int next; }g[N]; int head[N],ct; int E[2*N],R[N],D[2*N]; int dp[2*N][20],f[N],pow2[21]; bool vt[N]; int n,cnt; void init(){ for (int i = 0; i <= n; ++i){ f[i] = -1; head[i] = -1; } ct = 0; cnt = 0; CL(vt,false); } void add(int u,int v){ g[ct].v = v; g[ct].next = head[u]; head[u] = ct++; } //E,R,D对应的值 void dfs(int u,int dep){ vt[u] = true; E[cnt] = u; R[u] = cnt; D[cnt++] = dep; for (int i = head[u]; i != -1; i = g[i].next){ int v = g[i].v; if (!vt[v]){ dfs(v,dep + 1); E[cnt] = u; D[cnt++] = dep; } } } int MIN(int i,int j){ if (D[i] < D[j]) return i; else return j; } void init_rmq(){ int nn = 2*n - 1; int i,j; for (i = 0; i < nn; ++i) dp[i][0] = i; for (j = 1; pow2[j] <= nn; ++j){ for (i = 0; (i + pow2[j] - 1) < nn; ++i) dp[i][j] = MIN(dp[i][j - 1],dp[i + pow2[j - 1]][j - 1]); } } int rmq(int l,int r){ int k = (int)(log(1.0*(r - l + 1))/log(2.0)); return MIN(dp[l][k],dp[r - pow2[k] + 1][k]); } int main(){ //freopen("din.txt","r",stdin); int T,i; int x,y; for (i = 0; i < 20; ++i) pow2[i] = 1<<i; scanf("%d",&T); while (T--){ scanf("%d",&n); init(); for (i = 1; i < n; ++i){ scanf("%d%d",&x,&y); add(x,y); f[y] = x; } //找出根节点 for (i = 1; i <= n; ++i){ if (f[i] == -1){ break; } } cnt = 0; dfs(i,0); init_rmq(); scanf("%d%d",&x,&y); if (R[x] <= R[y]) printf("%d\n",E[rmq(R[x],R[y])]); else printf("%d\n",E[rmq(R[y],R[x])]); } return 0; }
tarjan离线处理:
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll __int64 #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 100007 #define N 10007 using namespace std; //freopen("din.txt","r",stdin); struct node{ int v; int next; }g[N]; int head[N],ct; bool vt[N]; vector<int>ask[N]; int f[N],pa[N],pre[N]; int n; int find(int x){ if (x != f[x]) f[x] = find(f[x]); return f[x]; } void Union(int x,int y){ x = find(x); y = find(y); f[x] = y; } void add(int u,int v){ g[ct].v = v; g[ct].next = head[u]; head[u] = ct++; } void LCA(int u){ int i; f[u] = u;//建立以当前节点为根的树 for (i = head[u]; i != -1; i = g[i].next){ int v = g[i].v; LCA(v); Union(u,v);//记住是u指向v pa[find(u)] = u;//记录该树的父节点 } vt[u] = true; int sz = ask[u].size(); for (i = 0; i < sz; ++i){ if (vt[ask[u][i]]){//如果同时访问就可求出lca printf("%d\n",pa[find(ask[u][i])]); } } } int main(){ //freopen("din.txt","r",stdin); int i; int T,x,y; scanf("%d",&T); while (T--){ scanf("%d",&n); ct = 0; CL(head,-1); CL(pre,-1); for (i = 1; i < n; ++i){ scanf("%d%d",&x,&y); add(x,y); pre[y] = x;//记录父节点主要在于找根 } for (i = 1; i <= n; ++i){ f[i] = i; ask[i].clear();//离线处理 } scanf("%d%d",&x,&y); ask[x].push_back(y); ask[y].push_back(x); CL(vt,false); //找父节点 for (i = 1; i <= n; ++i){ if (pre[i] == -1) break; } LCA(i); } return 0; }