Codeforces 757F Team Rocket Rises Again

题意

给一个n个点m条边的无向图和起点s,现在可以任意删掉一个除s以外的点,问最多有多少个点的最短路发生变化。
n<=200000,m<=300000

分析

其实这题就是问你把这个无向图构造一个最短路的DAG,求这个每个点能影响多少个点,其实也就是让你做支配树。

代码

#include <bits/stdc++.h>

#define pb(x) push_back(x)

const int N = 200005;
const long long INF = (long long)1e15;

typedef long long ll;

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}

int n,m,s;

struct Edge
{
    int to,next,c;
    bool op;
}e[N * 3];

int next[N];
int cnt;

void add(int x,int y,int z)
{
    e[++cnt].to = y, e[cnt].c = z, e[cnt].next = next[x], next[x] = cnt;
    e[++cnt].to = x, e[cnt].c = z, e[cnt].next = next[y], next[y] = cnt;
}

ll dis[N];
bool vis[N];

void spfa()
{
    for (int i = 1; i <= n; i++)
        dis[i] = INF;
    dis[s] = 0;
    vis[s] = 1;
    std::queue<int> Q;
    Q.push(s);
    while (!Q.empty())
    {
        int x = Q.front();
        Q.pop();
        for (int i = next[x]; i; i = e[i].next)
        {
            int v = e[i].to;
            if (dis[v] > dis[x] + e[i].c)
            {
                dis[v] = dis[x] + e[i].c;
                if (!vis[v])
                {
                    Q.push(v);
                    vis[v] = 1;
                }
            }
        }
        vis[x] = 0;
    }
}

int d[N];

std::vector<int> V[N];

void rebuild()
{
    memset(vis, 0, sizeof(vis));
    std::queue<int> Q;
    Q.push(s);
    while (!Q.empty())
    {
        int x = Q.front();
        Q.pop();
        for (int i = next[x]; i; i = e[i].next)
        {
            int v = e[i].to;
            if (dis[v] == dis[x] + e[i].c)
            {
                d[v]++;
                e[i].op = 1;
                V[v].pb(x);
                if (!vis[v])
                {
                    Q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
}

int a[N];
int tot;

void topSort()
{
    a[++tot] = s;
    for (int j = 1; j <= tot; j++)
    {
        int x = a[j];
        for (int i = next[x]; i; i = e[i].next)
        {
            if (e[i].op == 1)
            {
                d[e[i].to]--;
                if (!d[e[i].to])
                    a[++tot] = e[i].to;
            }
        }
    }
}

int fa[N][20];
int dep[N];

int lca(int x,int y)
{
    if (dep[x] < dep[y])
        std::swap(x,y);
    for (int i = 18; i >= 0; i--)
        if (dep[fa[x][i]] >= dep[y])
            x = fa[x][i];
    if (x == y)
        return x;
    for (int i = 18; i >= 0; i--)
        if (fa[x][i] != fa[y][i])
            x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}

int size[N];

void solve()
{
    for (int i = 1; i <= tot; i++)
    {
        int x = a[i];
        for (int j = 0; j < V[x].size(); j++)
            if (!fa[x][0])
                fa[x][0] = V[x][j];
            else fa[x][0] = lca(fa[x][0], V[x][j]);
        dep[x] = dep[fa[x][0]] + 1;
        for (int j = 1; j <= 18; j++)
            fa[x][j] = fa[fa[x][j - 1]][j - 1];
    }
    for (int i = tot; i >= 1; i--)
        size[a[i]]++, size[fa[a[i]][0]] += size[a[i]];
    int ans = 0;
    for (int i = 2; i <= tot; i++)
        ans = std::max(ans, size[a[i]]);
    printf("%d\n",ans);
}

int main()
{
    n = read(), m = read(), s = read();
    for (int i = 1; i <= m; i++)
    {
        int x = read(), y = read(), z = read();
        add(x,y,z);
    }
    spfa();
    rebuild();
    topSort();
    solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值