poj 1330 LCA问题 (LCA问题转化为RMQ || tarjan算法)
LCA问题可以与RMQ问题互相转化,长郡中学 郭华阳的《RMQ&LCA问题》讲的很好。
这个博客也讲的很好:http://dongxicheng.org/structure/lca-rmq/
Run ID | User | Problem | Result | Memory | Time | Language | Code Length | Submit Time |
10873609 | xinghan0219 | 1330 | Accepted | 3176K | 47MS | G++ | 2000B | 2012-10-01 19:49:03 |
10546730 | xinghan0219 | 1330 | Accepted | 2032K | 63MS | G++ | 1756B | 2012-07-27 17:08:33 |
RMQ问题:http://www.cnblogs.com/Missa/archive/2012/10/01/2709686.html
tarjan算法模版:http://www.cnblogs.com/Missa/archive/2012/10/01/2709749.html
RMQ+dfs:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 6 using namespace std; 7 8 #define MAXN 10005 9 #define MAXM 105 10 #define inf 0x7ffffff 11 int n; 12 struct Edge 13 { 14 int v,next; 15 }edge[MAXN]; 16 int head[MAXN]; 17 int e; 18 19 void clear()//初始化 20 { 21 memset(head,-1,sizeof(head)); 22 e=0; 23 } 24 void addEdge(int u,int v)//加边 25 { 26 edge[e].v=v; 27 edge[e].next=head[u];head[u]=e++; 28 } 29 int first[MAXN];//结点在搜索顺序数组中最先出现的位置(下标) 30 int occur[MAXN<<1];//结点在出现的顺序数组重复的也要记录 31 int depth[MAXN<<1];//结点在搜索树中的深度,与occur相对应 32 int dp_min[MAXN<<1][20];//dp_min[i][j] 表示从第i个位置开始的2^j个元素中的最小值的下标 33 int m=0;//不断记录出现的下标 34 35 void dfs(int u,int deep) 36 { 37 occur[++m]=u;//进入该点时进行记录 38 depth[m]=deep; 39 if(!first[u]) 40 first[u]=m; 41 for(int i=head[u];i+1;i=edge[i].next) 42 { 43 dfs(edge[i].v,deep+1); 44 occur[++m]=u;//访问子树返回也要标记 45 depth[m]=deep; 46 } 47 } 48 void init() 49 { 50 clear(); 51 m=0; 52 memset(first,0,sizeof(first)); 53 bool in[MAXN];//记录结点有无入度 54 memset(in,false,sizeof(in)); 55 int u=0,v=0; 56 scanf("%d",&n); 57 for(int i=1;i<n;i++)//注意此题只有n-1条边 58 { 59 scanf("%d%d",&u,&v); 60 addEdge(u,v);//u->v单向 61 in[v]=true; 62 } 63 for(int i=1;i<=n;i++)//从根开始dfs 64 { 65 if(!in[i]) 66 { 67 dfs(i,0); 68 break; 69 } 70 } 71 } 72 73 void RMQ_init(int num) 74 { 75 for(int i=1;i<=num;i++) 76 dp_min[i][0]=i;//注意dp_min存的不是最小值,而是最小值的下标 77 for(int j=1;j<20;j++) 78 for(int i=1;i<=num;i++) 79 { 80 if(i+(1<<j)-1 <= num) 81 { 82 dp_min[i][j] = depth[dp_min[i][j-1]] < depth[dp_min[i+(1<<(j-1))][j-1]] ? dp_min[i][j-1] : dp_min[i+(1<<(j-1))][j-1]; 83 } 84 } 85 } 86 87 int RMQ_min(int a,int b) 88 { 89 int l=first[a],r=first[b];//得到区间左右端点 90 if(l>r) 91 { 92 int t=l; 93 l=r; 94 r=t; 95 } 96 int k=(int)(log(double(r-l+1))/log(2.0)); 97 int min_id=depth[dp_min[l][k]]<depth[dp_min[r-(1<<k)+1][k]]?dp_min[l][k]:dp_min[r-(1<<k)+1][k];//最小值下标 98 return occur[min_id];//取得当前下标表示的结点 99 } 100 101 int main() 102 { 103 int t; 104 int a,b; 105 scanf("%d",&t); 106 while(t--) 107 { 108 init(); 109 RMQ_init(m); 110 scanf("%d%d",&a,&b); 111 printf("%d\n",RMQ_min(a,b)); 112 } 113 return 0; 114 }
tarjan算法:
1 //O(n+Q) 2 3 #include <iostream> 4 #include <cstdio> 5 #include <cstring> 6 #include <vector> 7 8 using namespace std; 9 10 #define MAXN 10001 11 12 int n,fa[MAXN]; 13 int rank[MAXN]; 14 int indegree[MAXN]; 15 int vis[MAXN]; 16 vector<int> hash[MAXN],Qes[MAXN]; 17 int ances[MAXN];//祖先 18 19 20 void init(int n) 21 { 22 for(int i=0;i<=n;i++) 23 { 24 fa[i]=i; 25 rank[i]=0; 26 indegree[i]=0; 27 vis[i]=0; 28 ances[i]=0; 29 hash[i].clear(); 30 Qes[i].clear(); 31 } 32 } 33 34 int find(int x) 35 { 36 if(x != fa[x]) 37 fa[x]=find(fa[x]); 38 return fa[x]; 39 } 40 41 void unio(int x,int y) 42 { 43 int fx=find(x),fy=find(y); 44 if(fx==fy) return ; 45 if(rank[fy]<rank[fx]) 46 fa[fy]=fx; 47 else 48 { 49 fa[fx]=fy; 50 if(rank[fx]==rank[fy]) 51 rank[fy]++; 52 } 53 } 54 55 void Tarjan(int u) 56 { 57 ances[u]=u; 58 int i,size = hash[u].size(); 59 for(i=0;i<size;i++) 60 { 61 Tarjan(hash[u][i]);//递归处理儿子 62 unio(u,hash[u][i]);//将儿子父亲合并,合并时会将儿子的父亲改为u 63 ances[find(u)]=u;//此时find(u)仍为u,即 64 } 65 vis[u]=1; 66 67 //查询 68 size = Qes[u].size(); 69 for(i=0;i<size;i++) 70 { 71 if(vis[Qes[u][i]]==1)//即查询的另一个结点开始已经访问过,当前的u在此回合访问。 72 { 73 printf("%d\n",ances[find(Qes[u][i])]);//由于递归,此时还是在u 74 return; 75 } 76 } 77 } 78 79 int main() 80 { 81 int t; 82 int i,j; 83 scanf("%d",&t); 84 while(t--) 85 { 86 scanf("%d",&n); 87 init(n); 88 int s,d; 89 for(i=1;i<=n-1;i++) 90 { 91 scanf("%d%d",&s,&d); 92 hash[s].push_back(d); 93 indegree[d]++; 94 } 95 scanf("%d%d",&s,&d); 96 Qes[s].push_back(d); 97 Qes[d].push_back(s); 98 for(j=1;j<=n;j++) 99 { 100 if(indegree[j]==0) 101 { 102 Tarjan(j); 103 break; 104 } 105 } 106 } 107 return 0; 108 }