BJ模拟 Problem B: Team Rocket Rises Again【最短路+支配树】

题目描述:

给一张n个点,m条边,有源点S的无向图,求对于每个点,有多少个点的最短路必经过它。n<=100000,m<=300000

解题思路:

先跑一边最短路建出最短路DAG,然后就是求每个点的必经点,直接上支配树即可。

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
#define pb push_back
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=100005,M=600005;
int n,m,S;
int tot,first[N],nxt[M],to[M],w[M],exist[N];ll dis[N];queue<int>q;
int idx,dfn[N],id[N],fa[N],sdom[N],idom[N],last[N],minp[N],size[N];
vector<int>pre[N],bkt[N],g1[N],g2[N];
void add(int x,int y,int z)
{
    nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
}
void SPFA()
{
    for(int i=1;i<=n;i++)dis[i]=1e18;
    dis[S]=0,q.push(S),exist[S]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();exist[u]=0;
        for(int e=first[u];e;e=nxt[e])
        {
            int v=to[e];
            if(dis[v]>dis[u]+w[e])
            {
                dis[v]=dis[u]+w[e];
                if(!exist[v])q.push(v),exist[v]=1;
            }
        }
    }
    for(int u=1;u<=n;u++)
        for(int e=first[u];e;e=nxt[e])if(dis[u]+w[e]==dis[to[e]])
            g1[u].pb(to[e]),pre[to[e]].pb(u);
}
void dfs1(int u)
{
    id[dfn[u]=sdom[u]=++idx]=u;
    for(int v:g1[u])if(!dfn[v])fa[v]=u,dfs1(v);
}
int find(int x)
{
    if(last[x]==x)return x;
    int fx=find(last[x]);
    if(sdom[minp[last[x]]]<sdom[minp[x]])minp[x]=minp[last[x]];
    return last[x]=fx;
}
inline int eval(int u){find(u);return minp[u];}
void build()
{
    for(int i=1;i<=n;i++)last[i]=minp[i]=i;
    for(int i=idx;i>=2;i--)
    {
        int u=id[i];
        for(int v:pre[u])sdom[u]=min(sdom[u],sdom[eval(v)]);
        bkt[id[sdom[u]]].pb(u);last[u]=fa[u];
        for(int v:bkt[fa[u]])
        {
            int w=eval(v);
            idom[v]=sdom[v]==sdom[w]?fa[u]:w;
        }
        bkt[fa[u]].clear();
    }
    for(int i=2,u;i<=idx;i++)
    {
        u=id[i];
        idom[u]=idom[u]==id[sdom[u]]?idom[u]:idom[idom[u]];
        g2[idom[u]].pb(u);
    }
}
void dfs2(int u)
{
    size[u]=1;
    for(int v:g2[u])dfs2(v),size[u]+=size[v];
}
int main()
{
    //freopen("lx.in","r",stdin);
    int x,y,z;
    n=getint(),m=getint(),S=getint();
    while(m--)
    {
        x=getint(),y=getint(),z=getint();
        add(x,y,z),add(y,x,z);
    }
    SPFA();dfs1(S);build();dfs2(S);
    for(int i=1;i<=n;i++)printf("%d\n",size[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cdsszjj/article/details/80218683