题意:
寻找图中从一条边到另一条边的路径上必须经过的点的个数
思路:
首先必经过的一定是割点 因此可以先做点双连通然后缩点 缩完点后形成了树 而且树上的路径是满足“非割点-割点-非割点-割点-…”这样的模式的 路径u->v只需要求出他们的lca 则答案可以通过(dis[u]+dis[v]-dis[lca]*2)/2算出
注意:
这题缩点是通过边来进行的 因为这样可以使每条边都在一个连通块中 —— by wuyiqi
PS:
代码中缩点的部分借鉴了 Sd.无心插柳 的代码 感觉很好理解 Orz Sd.无心插柳 Orz wuyiqi
代码:
#pragma comment(linker, "/STACK:102400000,102400000") #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<cmath> #include<map> #include<set> #include<vector> using namespace std; typedef long long LL; #define N 20010 #define M 400010 #define inf 2147483647 int n,m,q,tot,idx,top; int fu[M],fv[M]; int head[N],dfn[N],low[N],belong[M],st[M],Tmp[N]; int vis[N],dis[N],lca[N][20]; struct edge { int u,v,next; bool flag; }ed[M]; pair<int,int> E[M]; void init() { tot=idx=top=0; memset(head,-1,sizeof(head)); memset(dfn,-1,sizeof(dfn)); memset(Tmp,0,sizeof(Tmp)); memset(vis,0,sizeof(vis)); } void add(int u,int v) { ed[tot].u=u; ed[tot].v=v; ed[tot].flag=false; ed[tot].next=head[u]; head[u]=tot++; } void tarjan(int u,int fa) { int i,j,v; dfn[u]=low[u]=++idx; for(i=head[u];~i;i=ed[i].next) { v=ed[i].v; if(ed[i].flag||dfn[v]>=dfn[u]) continue; ed[i].flag=ed[i^1].flag=true; st[++top]=i; if(dfn[v]==-1) { tarjan(v,u); low[u]=min(low[u],low[v]); if(dfn[u]<=low[v]) { n++; do { j=st[top--]; if(Tmp[ed[j].v]!=n) { E[m++]=make_pair(n,ed[j].v); Tmp[ed[j].v]=n; } if(Tmp[ed[j^1].v]!=n) { E[m++]=make_pair(n,ed[j^1].v); Tmp[ed[j^1].v]=n; } belong[j>>1]=n; }while(j!=i); } } else low[u]=min(low[u],dfn[v]); } } void maketable(int u,int from) { int i,v; vis[u]=1; dis[u]=dis[from]+1; lca[u][0]=from; for(i=1;i<20;i++) lca[u][i]=lca[lca[u][i-1]][i-1]; for(i=head[u];~i;i=ed[i].next) { v=ed[i].v; if(v!=from&&!vis[v]) maketable(v,u); } } int findlca(int u,int v) { if(dis[v]>dis[u]) swap(u,v); int i,tmp=dis[u]-dis[v]; for(i=19;tmp;i--) { if(tmp>=(1<<i)) { tmp-=(1<<i); u=lca[u][i]; } } if(u==v) return u; for(i=19;i>=0;i--) { if(lca[u][i]!=lca[v][i]) { u=lca[u][i]; v=lca[v][i]; } } return lca[u][0]; } int main() { int i,j,u,v,f; while(~scanf("%d%d",&n,&m)) { if(!n&&!m) break; init(); for(i=1;i<=m;i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); fu[i]=u; fv[i]=v; } m=0; for(i=1;i<=n;i++) { if(dfn[i]==-1) tarjan(i,i); } tot=0; memset(head,-1,sizeof(head)); for(i=0;i<m;i++) { add(E[i].first,E[i].second); add(E[i].second,E[i].first); } for(i=1;i<=n;i++) { if(!vis[i]) maketable(i,0); } scanf("%d",&q); while(q--) { scanf("%d%d",&i,&j); u=belong[i-1]; v=belong[j-1]; f=findlca(u,v); printf("%d\n",(dis[u]+dis[v]-dis[f]*2)/2); } } return 0; }
UVALive 4839 HDU 3686 Traffic Real Time Query System
原文地址:http://blog.csdn.net/houserabbit/article/details/38943763