题目链接
题意:
问从一条边到另一条边的必经点。
分析:
首先,问必经点,当然是要点双缩点(圆方树)啦,关键是把边映射到哪一点上,其实直接放在某联通分量的方点上就行,但是这个点并不好找,所以我们考虑一个别的办法。
我们这样去考虑,如果这个边连着的有一个点不是割点,那么就直接给它找到方点就行了,但是如果是割点呢?那么我们就找一次所有的与这两个点相邻的方点,然后找到就好了,但是这样的复杂度我们并不喜欢,我们可以考虑换一种想法,有了圆方树之后,我们要找路径间的圆点的个数,其实你想一想,如果以圆点开头圆点结尾就可以直接根据总点数求出(当然不这样写也行),然后就是开始配对,边1连接的两点和边2连接的两点相配,分别求出路径上圆点的个数(不包括起点和终点),答案是什么呢?取max,为啥,因为都不包括起点和终点,为了防止某点为割点(+1并不行,是割点不一定就要过),我们只能进行取max,然后4次lca,最后找出答案。
代码:
#include <cstdio> #include <string> #include <cstring> using namespace std; const int maxn=2e4+10; const int maxm=1e5+10; struct E{ int to; int next; int from; }ed[maxm*2]; int head[maxn]; int tot; void J(int a,int b){ tot++; ed[tot].to=b; ed[tot].from=a; ed[tot].next=head[a]; head[a]=tot; } int dfn[maxn]; int low[maxn]; int sta[maxn]; int top; int js; int s; int n; E edx[maxn*2]; int headx[maxn]; int totx; void Jx(int a,int b){ totx++; edx[totx].to=b; edx[totx].next=headx[a]; headx[a]=totx; } void tarjan(int x){//缩点 js++; low[x]=dfn[x]=js; top++; sta[top]=x; for(int i=head[x];i;i=ed[i].next){ if(dfn[ed[i].to]) low[x]=min(low[x],dfn[ed[i].to]); else{ tarjan(ed[i].to); low[x]=min(low[ed[i].to],low[x]); if(low[ed[i].to]==dfn[x]){ s++; int tmp; do{ tmp=sta[top]; top--; Jx(n+s,tmp); Jx(tmp,s+n); }while(tmp!=ed[i].to); Jx(x,n+s); Jx(n+s,x); } } } } int vis[maxn]; int dep[maxn]; int fa[maxn]; void Dfs(int x){ vis[x]=1; for(int i=headx[x];i;i=edx[i].next){ if(vis[edx[i].to]) continue; dep[edx[i].to]=dep[x]+1; fa[edx[i].to]=x; Dfs(edx[i].to); } } int lc(int a,int b){//lca if(dep[a]<dep[b]) swap(a,b); while(dep[a]>dep[b]) a=fa[a]; if(a==b) return a; while(a!=b){ a=fa[a]; b=fa[b]; } return a; } int l(int a,int b){ return (dep[a]+dep[b]-2*dep[lc(a,b)])/2-1; } int main(){ int m; while(~scanf("%d%d",&n,&m)&&(m||n)){ tot=0; memset(head,0,sizeof(head)); totx=0; memset(headx,0,sizeof(headx)); int js1,js2; js=0; memset(dfn,0,sizeof(dfn)); top=0; s=0; memset(vis,0,sizeof(vis)); for(int i=1;i<=m;i++){ scanf("%d%d",&js1,&js2); J(js1,js2); J(js2,js1); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n+s;i++) if(!vis[i]) Dfs(i); int q; scanf("%d",&q); for(int i=1;i<=q;i++){ scanf("%d%d",&js1,&js2); printf("%d ",max(max(l(ed[js1*2].to,ed[js2*2].to),l(ed[js1*2].from,ed[js2*2].to)),max(l(ed[js1*2].to,ed[js2*2].from),l(ed[js1*2].from,ed[js2*2].from))));//分别计算 } } return 0; }