LCA
来源:互联网 发布:阿里云邮箱iphone7 编辑:程序博客网 时间:2024/06/03 13:14
LCA
倍增法
在线算法
时间复杂度:
- 预处理:
O(N) - 查询:
O(log2N)
这里应用到了树中很重要的倍增思想,其实很多基础的树上操作题都可以用与 LCA 相似的方法求解。
#include<cstdio>#include<cmath>using namespace std;const int MAXN=1000005;int N,M,S;int anc[MAXN][20],deep[MAXN];void swap(int & a,int & b){int t=a;a=b;b=t;}struct E{int to,next;} e[MAXN];int ecnt,G[MAXN];void addEdge(int u, int v){e[++ecnt]=(E){v,G[u]};G[u]=ecnt;}void dfs(int u,int ln){ for(int i=G[u];i;i=e[i].next) { int v=e[i].to; if(v==ln) continue; deep[v]=deep[u]+1; anc[v][0]=u; dfs(v,u); }}void getReady(){ for(int i=1;(1<<i)<=N;i++) { for(int j=1;j<=N;j++) anc[j][i]=anc[anc[j][i-1]][i-1]; }}int getlca(int x, int y){ int i; if(deep[x]<deep[y]) swap(x,y); int maxlogn=floor(log(N)/log(2)); for(i=maxlogn;i>=0;i--) { if(deep[x]-(1<<i)>=deep[y]) x=anc[x][i]; } if(x==y) return x; for(i=maxlogn;i>=0;i--) { if(anc[x][i]!=anc[y][i]) { x=anc[x][i]; y=anc[y][i]; } } return anc[x][0];}int main(){ scanf("%d%d%d",&N,&M,&S); for(int i=1;i<N;i++) { int u,v;scanf("%d%d",&u,&v); addEdge(u,v);addEdge(v,u); } dfs(S,S); getReady(); for(int i=1;i<=M;i++) { int a,b; scanf("%d%d",&a,&b); printf("%d\n",getlca(a,b)); } return 0;}
Tarjan法
离线算法
利用并查集,注意 dfs 时先执行递归操作再加入并查集。
#include<iostream>#include<cstdio>using namespace std;const int MAXN=1000005;int N,M,S;//CFSint E{int to,next;} e[MAXN];int ecnt,G[MAXN];void addEdge(int u,int v){e[++ecnt]=(E){v,G[u]};G[u]=ecnt;}//UFSint fa[MAXN];void getFa(int x){return fa[x]==x?fa[x]:fa[x]=getFa(x);}int A{int to,num,next;} ask[MAXN];int acnt,head[MAXN];void addAsk(int x,int y,int z){ask[++acnt]=(A){y,z,head[x]};head[x]=acnt;}int ans[MAXN],vis[MAXN];void calLCA(int u){ vis[u]=true,fa[u]=x; int i; for(i=G[u];i;i=e[i].next) { int v=e[i].to; if(!vis[v]) { LCA(v); fa[v]=x; } } for(i=head[u];i;i=ask[i].next) { int v=ask[i].to,num=ask[i].num; if(vis[v]) ask[num]=getFa(v); }}int main(){ scanf("%d%d%d",&N,&M,&S); int i; for(i=1;i<N;i++) { int u,v;scanf("%d%d",&u,&v); addEdge(u,v);addEdge(v,u); } for(i=1;i<=M;i++) { int x,y;scanf("%d%d",&x,&y); addAsk(x,y,i);addAsk(y,x,i); } calLCA(S); for(i=1;i<=M;i++) printf("%d\n",ans[i]); return 0;}
RMQ法
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;const int MAXN=500000,MAXM=100;int a[MAXN+1],pa=0;int na[MAXN+1];int f[MAXN+1][MAXM+1];int head[MAXN+1],ecnt;struct node{int to,next;} edge[MAXN+1];void add(int x,int y){ ecnt++; edge[ecnt].to=y; edge[ecnt].next=head[x]; head[x]=ecnt;}void Init(){ for (int i = 1; i <= pa; i++) f[i][0] = a[i]; for (int k = 1; (1 << k) <= pa; k++) for (int i = 1; i + (1 << k) - 1 <= pa; i++) f[i][k] = min(f[i][k - 1], f[i + (1 << (k - 1))][k - 1]);}int RMQ(int l, int r){ int k = 0; while( (1 << (k + 1)) <= r - l + 1 ) k++; return min( f[l][k], f[r - (1 << k) + 1][k] );}void dfs(int x,int d){ for(int tmp=head[x];tmp;tmp=edge[tmp].next) { a[++pa]=d;na[pa]=x; dfs(edge[tmp].to,d+1); } a[++pa]=d;na[pa]=x;}int main(){ int u,v,N,M,S,x,y,xp,yp; cin>>N>>M>>S; for(int i=1;i<=N-1;i++) cin>>u>>v,add(v,u); dfs(S,1); Init(); for(int i=1;i<=M;i++) { cin>>x>>y; for(int i=1;i<=pa;i++) if(na[i]==x){xp=i;break;} for(int i=1;i<=pa;i++) if(na[i]==y){yp=i;break;} if(xp>yp) swap(xp,yp); cout<<na[RMQ(xp,yp)]<<endl; } return 0;}
0 0
- LCA
- LCA
- lca
- LCA
- LCA
- lca
- LCA
- LCA
- LCA
- LCA
- LCA
- lca
- lca
- LCA
- lca
- LCA
- LCA
- LCA
- secureCRT The remote system refused the connection
- [生存志] 第125节 针道针具取穴
- 开源第三方登录组件OAuthLogin2.0 架构解析及开源地址
- 基于MVC的三级联动
- C3-4 斐波那契数列选做题
- LCA
- XSLT 处理程序是如何工作的
- 归并、二分插入排序
- 网页数据抓取之淘宝数据
- VS2010界面主题更换全过程
- 微信网页授权开发流程
- [生存志] 第126节 本输营气寿夭
- Tomcat - DOS下任意位置启动Tomcat
- 插件化开发---Hook之AMS\PMS、startActivity2种方式