首先介绍一下LCA
LCA(Least Common Ancestor)最近公共祖先,顾名思义,是指树上两点到根节点路径最早出现的公共节点,目前主要有两种算法
一、在线的倍增算法(可在算出lca同时计算最小(大)权值,路径长度)
二、离线的Tarjan(时间复杂度较小,但只能求出lca)
------------------------------------------------------------------------------------------------------------------------------------
两相抉择,我选择了Tarjan算法。
tarjan算法简单来说就是DFS+并查集,每次dfs到一个节点,先dfs它的儿子节点,这样就解决了它儿子的lca问题(并查集)。不断的DFS一棵树以后也就解决了所有询问,先贴STANDARD CODE:
intf[maxn],fs[maxn];//并查集父节点 父节点个数 boolvit[maxn]; intanc[maxn];//祖先 vector<int> son[maxn];//保存树 vector<int> qes[maxn];//保存查询 typedefvector<int>::iterator IT; intFind(intx) { if(f[x]==x)returnx; elsereturnf[x]=Find(f[x]); } voidUnion(intx,inty)//启发式合并 { x=Find(x);y=Find(y); if(x==y)return; if(fs[x]<=fs[y]) f[x]=y,fs[y]+=fs[x]; elsef[y]=x,fs[x]+=fs[y]; } voidlca(intu) { anc[u]=u; for(IT v=son[u].begin();v!=son[u].end();++v)//穷举儿子节点 { lca(*v); Union(u,*v); anc[Find(u)]=u;//解决儿子的lca } vit[u]=true; for(IT v=qes[u].begin();v!=qes[u].end();++v) { if(vit[*v]) printf("LCA(%d,%d):%d\n",u,*v,anc[Find(*v)]); } }//(来自scturtle)
某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
你的任务是帮助该商人计算一下他的最短旅行时间。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; vector<int> son[50001][2]; vector<int> qes[75001][2]; vector<int> anc[50001][2]; int n,m,q; bool f[50001]={false}; int father[50001][2]; int ans[75001]={0}; int find(int x) { int j; if (father[x][0]!=x) { j=find(father[x][0]); father[x][1]+=father[father[x][0]][1]; father[x][0]=j; } return father[x][0]; } void LCA(int x,int y) { int i,root; for (i=0;i<son[x][0].size();++i) if (son[x][0][i]!=y) { LCA(son[x][0][i],x); father[son[x][0][i]][0]=x; father[son[x][0][i]][1]=son[x][1][i]; } f[x]=true; for (i=0;i<qes[x][0].size();++i) if (f[qes[x][0][i]]) { root=find(qes[x][0][i]); anc[root][0].push_back(x); anc[root][1].push_back(qes[x][1][i]); ans[qes[x][1][i]]=father[qes[x][0][i]][1]; } for (i=0;i<anc[x][0].size();++i) { find(anc[x][0][i]); ans[anc[x][1][i]]+=father[anc[x][0][i]][1]; } } int main() { int u,v,w,i,j; scanf("%d",&n); memset(father,0,sizeof(father)); for (i=0;i<=n-1;++i) {father[i][0]=i; anc[i][0].clear(); anc[i][1].clear(); son[i][0].clear(); son[i][1].clear(); qes[i][0].clear(); qes[i][1].clear();} for (i=1;i<=n-1;++i) { scanf("%d%d%d",&u,&v,&w); son[u][0].push_back(v); son[u][1].push_back(w); son[v][0].push_back(u); son[v][1].push_back(w); } scanf("%d",&q); for (i=1;i<=q;++i) { scanf("%d%d",&u,&v); if (u!=v) { qes[u][0].push_back(v); qes[u][1].push_back(i); qes[v][0].push_back(u); qes[v][1].push_back(i); } } LCA(1,-1); for(i=1;i<=q;++i) cout<<ans[i]<<endl; } code 1036 #include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; vector<int> son[30001]; vector<int> qes[100001]; vector<int> anc[30001][2]; int n,m; bool f[30001]={false}; int father[30001][2]; long long ans; int find(int x) { int j; if (father[x][0]!=x) { j=find(father[x][0]); father[x][1]+=father[father[x][0]][1]; father[x][0]=j; } return father[x][0]; } void LCA(int x,int y) { int i,root; for (i=0;i<son[x].size();++i) if (son[x][i]!=y) { LCA(son[x][i],x); father[son[x][i]][0]=x; father[son[x][i]][1]=1; } f[x]=true; for (i=0;i<qes[x].size();++i) if (f[qes[x][i]]) { root=find(qes[x][i]); anc[root][0].push_back(x); anc[root][1].push_back(qes[x][i]); } for (i=0;i<anc[x][0].size();++i) { find(anc[x][0][i]); find(anc[x][1][i]); ans+=father[anc[x][0][i]][1]+father[anc[x][1][i]][1]; } } int main() { int u,v,i,j; scanf("%d",&n); memset(father,0,sizeof(father)); for (i=1;i<=n;++i) {father[i][0]=i;anc[i][1].clear();anc[i][1].clear();son[i].clear();qes[i].clear();} for (i=1;i<=n-1;++i) { scanf("%d%d",&u,&v); son[u].push_back(v); son[v].push_back(u); } scanf("%d",&m); u=1; for (i=1;i<=m;++i) { scanf("%d",&v); if (u!=v) { qes[u].push_back(v); qes[v].push_back(u); } u=v; } ans=0; LCA(1,0); cout<<ans<<endl; }
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> using namespace std; struct hp{ int u,v,w; }a[55001]; int father[15001][2],ans[35001]={0}; vector<int> qes[35001][3]; vector<int> son[35001][3]; vector<int> anc[15001][3]; bool f[15001]={false}; int cmp(const hp &a,const hp &b) { if (a.w>b.w) return 1; else return 0; } int find(int x) { if (father[x][0]==x) return x; return find(father[x][0]); } int findx(int x) { int j; if (father[x][0]!=x) { j=findx(father[x][0]); father[x][1]=min(father[x][1],father[father[x][0]][1]); father[x][0]=j; } return father[x][0]; } void LCA(int x,int y) { int i,root; for (i=0;i<son[x][1].size();++i) if (son[x][1][i]!=y) { LCA(son[x][1][i],x); father[son[x][1][i]][0]=x; father[son[x][1][i]][1]=son[x][2][i]; } f[x]=true; for (i=0;i<qes[x][1].size();++i) if (f[qes[x][1][i]]) { root=findx(qes[x][1][i]); anc[root][0].push_back(qes[x][2][i]); anc[root][1].push_back(x); anc[root][2].push_back(qes[x][1][i]); } for (i=0;i<anc[x][0].size();++i) { findx(anc[x][1][i]); findx(anc[x][2][i]); ans[anc[x][0][i]]=min(father[anc[x][1][i]][1],father[anc[x][2][i]][1]); } } int main() { int u,v,k,r1,r2,i,j,n,m,q,root; //freopen("truck.in","r",stdin); //freopen("truck.out","w",stdout); scanf("%d%d",&n,&m); memset(father,127,sizeof(father)); for (i=1;i<=n;++i) {son[i][1].clear(); son[i][2].clear(); qes[i][1].clear(); qes[i][2].clear(); father[i][0]=i;} for (i=1;i<=m;++i) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); sort(a+1,a+m+1,cmp); k=0; for (i=1;i<=m;++i) { r1=find(a[i].u); r2=find(a[i].v); if (r1!=r2) { father[r1][0]=r2; u=a[i].u; v=a[i].v; son[u][1].push_back(v); son[u][2].push_back(a[i].w); son[v][1].push_back(u); son[v][2].push_back(a[i].w); k++; } if (k==n-1) break; } scanf("%d",&q); for (i=1;i<=q;++i) { scanf("%d%d",&u,&v); if (find(u)!=find(v)) ans[i]=-1; else { qes[u][1].push_back(v); qes[u][2].push_back(i); qes[v][1].push_back(u); qes[v][2].push_back(i); } } for (i=1;i<=n;++i) father[i][0]=i; for (i=1;i<=n;++i) if (!f[i]) LCA(i,0); for (i=1;i<=q;++i) printf("%d\n",ans[i]); //fclose(stdin); //fclose(stdout); }
<span style="font-family:SimSun;"> </span>