Traffic Real Time Query System,题解

题目链接

题意:

  问从一条边到另一条边的必经点。

分析:

  首先,问必经点,当然是要点双缩点(圆方树)啦,关键是把边映射到哪一点上,其实直接放在某联通分量的方点上就行,但是这个点并不好找,所以我们考虑一个别的办法。

  我们这样去考虑,如果这个边连着的有一个点不是割点,那么就直接给它找到方点就行了,但是如果是割点呢?那么我们就找一次所有的与这两个点相邻的方点,然后找到就好了,但是这样的复杂度我们并不喜欢,我们可以考虑换一种想法,有了圆方树之后,我们要找路径间的圆点的个数,其实你想一想,如果以圆点开头圆点结尾就可以直接根据总点数求出(当然不这样写也行),然后就是开始配对,边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;
}
原文地址:https://www.cnblogs.com/wish-all-ac/p/12830180.html