学习LCA( 最近公共祖先·二)
http://poj.org/problem?id=1986
离线找u,v之间的最小距离(理解推荐)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; char s[2]; const int M=1e5+5; const int N=2e4+4; struct node{ int v,w,nextt; }e[M]; struct NODE{ int v,dis,nextt; }g[M]; int fa[M],head[M],Head[M],vis[M],dis[M]; int tot,TOT; void addedge(int u,int v,int w){ e[tot].v=v; e[tot].w=w; e[tot].nextt=head[u]; head[u]=tot++; e[tot].v=u; e[tot].w=w; e[tot].nextt=head[v]; head[v]=tot++; } ///存储询问的u,v void ADDedge(int u,int v){ g[TOT].v=v; g[TOT].nextt=Head[u]; Head[u]=TOT++; g[TOT].v=u; g[TOT].nextt=Head[v]; Head[v]=TOT++; } int Find(int x){ return fa[x]==x?x:fa[x]=Find(fa[x]); } void LCA(int u){ fa[u]=u; vis[u]=true; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(!vis[v]){ dis[v]=dis[u]+e[i].w; LCA(v); fa[v]=u; } } for(int i=Head[u];~i;i=g[i].nextt){ int v=g[i].v; if(vis[v]){ g[i].dis=dis[u]+dis[v]-2*dis[Find(v)]; g[i^1].dis=g[i].dis; } } } int main(){ int n,m; memset(head,-1,sizeof(head)); memset(Head,-1,sizeof(Head)); scanf("%d%d",&n,&m); while(m--){ int u,v,w; scanf("%d%d%d%s",&u,&v,&w,s); addedge(u,v,w); } int k; scanf("%d",&k); for(int i=0;i<k;i++){ int u,v; scanf("%d%d",&u,&v); ADDedge(u,v); } LCA(1); for(int i=0;i<TOT;i+=2){ printf("%d\n",g[i].dis); } return 0; }
http://hihocoder.com/problemset/problem/1067
tangin+离线
#include<bits/stdc++.h> using namespace std; const int M=1e5+10; struct node{ int to,index; node (int v,int index){ this->to=v; this->index=index; } }; vector<int>graph[M]; vector<node>e[M]; bool sign[M]; map<int,string>str; map<string,int>indx; int ans[M]; int f[M],color[M]; int tot,n,m,root; void init(){ tot=0; indx.clear(); memset(sign,false,sizeof(sign)); memset(color,0,sizeof(color)); memset(ans,0,sizeof(ans)); for(int i=0;i<M;i++){ graph[i].clear(); e[i].clear(); f[i]=i; } } int find(int x){ return x==f[x]?x:f[x]=find(f[x]); } int get_index(string x){ if(indx.count(x)) return indx[x]; indx[x]=++tot; str[tot]=x; return tot; } void input(){ cin>>n; for(int i=1;i<=n;i++){ string name1,name2; cin>>name1>>name2; int a=get_index(name1); int b=get_index(name2); graph[a].push_back(b); sign[b]=true; } cin>>m; for(int i=1;i<=m;i++){ string name1,name2; cin>>name1>>name2; int a=get_index(name1); int b=get_index(name2); e[a].push_back(node(b,i)); e[b].push_back(node(a,i)); } } void targin(int u){ color[u]=1; for(int i=0;i<e[u].size();i++){ int ID=e[u][i].index; if(ans[ID]) continue; int v=e[u][i].to; if(color[v]==0) //0代表v未访问过 continue; if(color[v]==1) //1代表正在访问,所以u和v的最近公共祖先就是v ans[ID]=v; if(color[v]==2) //2代表访问完毕的点,所以u和v的最近公共祖先就是v当前的祖先 ans[ID]=find(v); } for(int i=0;i<graph[u].size();i++){ int v=graph[u][i]; targin(v); //一个节点dfs完后,标记vv为访问完毕的点,并更新父节点 color[v]=2; f[v]=u; } } void solve(){ for(int i=1;i<=n;i++) if(!sign[i]) root=i; targin(root); for(int i=1;i<=m;i++) cout<<str[ans[i]]<<endl; } int main(){ init(); input(); solve(); return 0; }