最近公共祖先问题,,,今天学了LCA离线,,就做了这道题,dis[i]+dis[j]-2*dis[LCA(i,j)],dis是所有点到根节点的距离,,
LCA:从根节点开始形成一颗深搜树,刚开始每个节点属于一个集合,当回溯到节点u时,u的子树都已经遍历,把u的所有子树节点都加入到u这个集合中形成一个集合,然后处理关于u的查询,若查询(u,v)v已经遍历过,LCA(u,v)=(v所在集合的祖先)。
#include<stdio.h> #include<string.h> #define N 40001 int vis[N],dis[N],num,head[N],first[N],nume,n,m,f[N]; struct edge { int st,ed,next,w; }E[N*2]; struct point { int x,y,next,node; }p[410]; void addedge(int x,int y,int w) { E[num].st=x; E[num].ed=y; E[num].w=w; E[num].next=head[x]; head[x]=num++; } void addpoint(int x,int y) { p[nume].x=x; p[nume].y=y; p[nume].node=-1; p[nume].next=first[x]; first[x]=nume++; } int find(int a) { if(f[a]!=a) f[a]=find(f[a]); return f[a]; } void Tarjan(int u) { int i,v; vis[u]=1;//已经遍历 f[u]=u; //自己形成一个集合 for(i=head[u];i!=-1;i=E[i].next) { v=E[i].ed; if(vis[v]==1)continue; dis[v]=dis[u]+E[i].w;//到根节点的距离 Tarjan(v); f[v]=u;//把子树合并到父节点 } for(i=first[u];i!=-1;i=p[i].next) { int v=p[i].y; if(vis[v]==1)//如果v已经遍历 p[i/2*2].node=find(v);//找v所在集合的祖先 //因为加的是向边,所以把结果都存在第一条边上 } } int main() { int i,m,t,x,y,w; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); num=0; for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&w); addedge(x,y,w); addedge(y,x,w); } memset(first,-1,sizeof(first)); nume=0; for(i=0;i<m;i++) { scanf("%d%d",&x,&y); addpoint(x,y);//要加双向边,如果先遍历到x,y没遍历就没有结果, addpoint(y,x); } dis[1]=0; memset(vis,0,sizeof(vis)); Tarjan(1); for(i=0;i<nume;i+=2) printf("%d\n",dis[p[i].x]+dis[p[i].y]-2*dis[p[i].node]); } return 0; }
#include<stdio.h> #include<string.h> #define N 40001 int head[N],num,n,dfs[N],father[N],vis[N],dis[N]; struct edge { int st,ed,next,w; }E[N*2]; void addedge(int x,int y,int w) { E[num].st=x; E[num].ed=y; E[num].w=w; E[num].next=head[x]; head[x]=num++; } void dfs1(int u) { int i,v; vis[u]=1; for(i=head[u];i!=-1;i=E[i].next) { v=E[i].ed; if(vis[v]==1)continue; dfs[v]=dfs[u]+1; father[v]=u; dis[v]=E[i].w; dfs1(v); } } int LCA(int x,int y) { int sum=0; while(dfs[x]>dfs[y]) { sum+=dis[x]; x=father[x]; } while(dfs[y]>dfs[x]) { sum+=dis[y]; y=father[y]; } while(x!=y) { sum+=(dis[x]+dis[y]); x=father[x]; y=father[y]; } return sum; } int main() { int i,k,t,x,y,w; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&k); memset(head,-1,sizeof(head)); num=0; for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&w); addedge(x,y,w); addedge(y,x,w); } memset(vis,0,sizeof(vis)); dis[1]=0; dfs[1]=0; father[1]=0; dfs1(1); while(k--) { scanf("%d%d",&x,&y); printf("%d\n",LCA(x,y)); } } return 0; }
作者:aixiaoling1314 发表于2013-8-2 16:55:27 原文链接
阅读:31 评论:0 查看评论