【洛谷P4320】道路相遇

缩点,圆方树

题目大意:

给定一张无向连通图,多次询问两个点之间所有路径的必经点个数。

题解:

缩点,建圆方树。

然后两点之间的圆点个数就是必经点个数。

对每个询问求 LCA 然后计算即可。

缩点部分时间复杂度 $O(n+m)$。

考前作为点双模板练习。CSP RP++

Code:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+6;
int n,m,head[N],cnt,dfn[N],low[N],idx,sta[N],top;
struct edge{
    int to,nxt;
}e[N<<1];
namespace tr{
    int n,head[N],cnt,tg[N],dep[N],dis[N],fa[N],sz[N],top[N],son[N];
    edge e[N<<1];
    inline void init(int n){
        tr::n=n;
        for(int i=1;i<=n;++i)tg[i]=1;
    }
    inline void addedge(int u,int v){
        e[++cnt]=(edge){v,head[u]},head[u]=cnt;
        e[++cnt]=(edge){u,head[v]},head[v]=cnt;
    }
    inline int newnode(){return ++n;}
    void dfs(int now){
        sz[now]=1;
        for(int i=head[now];i;i=e[i].nxt)
        if(!dep[e[i].to]){
            dep[e[i].to]=dep[now]+1,fa[e[i].to]=now;
            dis[e[i].to]=tg[e[i].to]+dis[now];
            dfs(e[i].to);
            sz[now]+=sz[e[i].to];
            if(!son[now]||sz[son[now]]<sz[e[i].to])son[now]=e[i].to;
        }
    }
    void dfs2(int now){
        if(son[now])top[son[now]]=top[now],dfs2(son[now]);
        for(int i=head[now];i;i=e[i].nxt)
        if(e[i].to!=son[now]&&dep[e[i].to]>dep[now])
        dfs2(top[e[i].to]=e[i].to);
    }
    inline int LCA(int x,int y){
        while(top[x]!=top[y])
        if(dep[top[x]]>dep[top[y]])x=fa[top[x]];else y=fa[top[y]];
        return dep[x]<dep[y]?x:y;
    }
    void work(){
        dfs(dep[1]=dis[1]=1),dfs2(1);
        int q;
        cin>>q;
        while(q--){
            int u,v;
            cin>>u>>v;
            int w=LCA(u,v);
            cout<<dis[u]+dis[v]-2*dis[w]+tg[w]<<'\n';
        }
    }
}
void dfs(int now){
    sta[++top]=now;
    dfn[now]=low[now]=++idx;
    for(int i=head[now];i;i=e[i].nxt)
    if(!dfn[e[i].to]){
        dfs(e[i].to);
        low[now]=min(low[now],low[e[i].to]);
        if(low[e[i].to]>=dfn[now]){
            int id=tr::newnode();
            tr::addedge(now,id);
            int v;
            do{
                v=sta[top--];
                tr::addedge(v,id);
            }while(v!=e[i].to);
        }
    }else low[now]=min(low[now],dfn[e[i].to]);
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(;m--;){
        int u,v;
        cin>>u>>v;
        e[++cnt]=(edge){v,head[u]},head[u]=cnt;
        e[++cnt]=(edge){u,head[v]},head[v]=cnt;
    }
    tr::init(n);
    for(int i=1;i<=n;++i)
    if(!dfn[i])dfs(i);
    tr::work();
    return 0;
}