CF757F Team Rocket Rises Again 最短路树+支配树

题目大意:
给你 n ( n <= 2 10 5 ) 个点 m ( m <= 3 10 5 ) 条边的无向图,每条边有长度 w ( 1 <= w <= 10 9 ) ,问删除某个点(不包括 s )最多能影响多少条从 s 出发到其他 n 1 个点的最短路。

分析:
先把最短路求出来,然后连成最短路树(其实是一个 D A G ), s 到任何点的最短路都在树上。
然后在这个 D A G 上建支配树,断掉某个点的答案就是它所在 d f s 树的子树上有多少个点能被它支配,直接用支配链转移即可。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#define LL long long

const int maxn=2e5+7;
const int maxe=3e5+7;
const LL inf=1e16+7;

using namespace std;

int n,m,s,x,y,cnt;
int ls[maxn],last[maxn],idom[maxn],sdom[maxn],fa[maxn];
int p[maxn],val[maxn],f[maxn],dfn[maxn],id[maxn];
vector <int> dom[maxn],pre[maxn];
int v[maxn];
LL dis[maxn],w;

struct edge{
    int x,y,next;
    LL w;
}e[maxe*2];

struct node{
    int y,next;
}g[maxe*2];

struct rec{
    int x;
    LL d;
};

priority_queue <rec> q;

bool operator <(rec x,rec y)
{
    return x.d>y.d;
}

void dij()
{
    for (int i=1;i<=n;i++) dis[i]=inf;
    dis[s]=0;
    q.push((rec){s,0});
    while (!q.empty())
    {
        rec u=q.top();
        q.pop();
        int x=u.x;
        if (v[x]) continue;
        v[x]=1;
        for (int j=last[x];j>0;j=e[j].next)
        {
            int y=e[j].y;
            if (dis[y]>dis[x]+e[j].w)
            {
                dis[y]=dis[x]+e[j].w;
                q.push((rec){y,dis[y]});
            }
        }
    }
}

void add(int x,int y)
{
    g[++cnt]=(node){y,ls[x]};
    ls[x]=cnt;
}

void dfs(int x)
{
    dfn[x]=++cnt;
    id[cnt]=x;
    for (int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        pre[y].push_back(x);
        if (!dfn[y])
        {
            fa[y]=x;
            dfs(y);
        }
    }
}

int smin(int x,int y)
{
    if (dfn[x]<dfn[y]) return x;
    return y;
}

int get(int x)
{
    if (p[x]==x) return x;
    int y=get(p[x]);
    if (dfn[sdom[val[p[x]]]]<dfn[sdom[val[x]]]) val[x]=val[p[x]];
    p[x]=y;
    return y;
}

void DMT()
{
    for (int i=cnt;i>0;i--)
    {
        int x=id[i];
        if (!pre[x].empty())
        {
            for (int j=0;j<pre[x].size();j++)
            {
                int y=pre[x][j];
                if (dfn[y]<dfn[x]) sdom[x]=smin(sdom[x],y);
                else
                {
                    get(y);
                    sdom[x]=smin(sdom[x],sdom[val[y]]);
                }
            }
        }
        pre[x].clear();
        p[x]=fa[x];
        dom[sdom[x]].push_back(x);
        if (!dom[fa[x]].empty())
        {
            for (int j=0;j<dom[fa[x]].size();j++)
            {
                int y=dom[fa[x]][j];
                get(y);
                int d=val[y];
                if (dfn[sdom[d]]>=dfn[sdom[y]]) idom[y]=sdom[y];
                                           else idom[y]=d;
            }
            dom[fa[x]].clear();
        }
    }
    for (int i=1;i<=cnt;i++)
    {
        int x=id[i];
        if (idom[x]!=sdom[x]) idom[x]=idom[idom[x]];
    }
    for (int i=cnt;i>0;i--)
    {
        x=id[i];
        f[idom[x]]+=f[x];
    }
}

int main()
{
    scanf("%d%d%d",&n,&m,&s);       
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&x,&y,&w);
        e[i].x=x;
        e[i].y=y;
        e[i].w=w;
        e[i].next=last[x];
        last[x]=i;
        e[i+m].x=y;
        e[i+m].y=x;
        e[i+m].w=w;
        e[i+m].next=last[y];
        last[y]=i+m;
    }   
    dij();
    for (int i=1;i<=m*2;i++)
    {
        int x=e[i].x,y=e[i].y;
        if (dis[x]+e[i].w==dis[y]) add(x,y);
    }   
    cnt=0;  
    dfs(s);
    for (int i=1;i<=n;i++)
    {
        p[i]=val[i]=sdom[i]=i;
        f[i]=1;
    }   
    DMT();
    int ans=0;
    for (int i=2;i<=cnt;i++)
    {
        int x=id[i];
        ans=max(ans,f[x]);
    }
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81605825