\(\sf Description\)

\(\text{Link.}\)

\(\sf Solution\)

首先一遍 \(\rm bfs\) 求出 \(1\) 到每个点的最短路,记它为 \(d_i\)。那么对于边 \(e(u,v)\)(不妨设 \(d_u\le d_v\)),如果有 \(d_v=d_u+1\),那么 \(v\) 就可以通过 \(u\) 得到最短路。那么,当一个点 \(v\) 所有的可以给它贡献最短路的点 \(u\)\(d\) 都变大时,就说明 \(d_v\) 也要变大了。

可以搞一个类似拓扑排序的东西,记 \(v\) 的所有的可以给它贡献最短路的点 \(u\) 的个数为 \(in_v\),当 \(in_v=0\) 时就可以将变大传递给 \(e(v,w)\) 的点 \(w\)。由于每条边增大后就不可能出现在最短路里,所以每条边只用删除一次。

时间复杂度应该是 \(\mathcal O(m)\) 的。

\(\sf Code\)

#include <cstdio>
#include <queue>
#include <iostream>
using namespace std;

const int N = 1e5 + 5;

bool vis[N << 1];
int u[N << 1], v[N << 1], in[N], cnt, ans, n, m, Q, dis[N], goal, dot[N << 2], nxt[N << 2], head[N];
queue <int> q;

void addEdge(const int u, const int v) {
    dot[++ cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
}

void bfs() {
    q.push(1); dis[1] = 1;
    while(! q.empty()) {
        int u = q.front(); q.pop();
        for(int i = head[u]; i; i = nxt[i]) {
            int v = dot[i];
            if(! dis[v]) dis[v] = dis[u] + 1, q.push(v);
        }
    }
}

void del() {
    q.push(goal);
    while(! q.empty()) {
        int e = q.front(); q.pop();
        if(vis[e]) continue;
        vis[e] = 1;
        int p = v[e]; -- in[p];
        if(in[p] == 0) {
            ++ ans;
            for(int i = head[p]; i; i = nxt[i])
                if(dis[p] + 1 == dis[dot[i]]) q.push(i + 1 >> 1);
        }
    }
}

int main() {
    scanf("%d %d %d", &n, &m, &Q);
    for(int i = 1; i <= m; ++ i) {
        scanf("%d %d", &u[i], &v[i]);
        addEdge(u[i], v[i]), addEdge(v[i], u[i]);
    }
    bfs();
    for(int i = 1; i <= n; ++ i)
        for(int j = head[i]; j; j = nxt[j])
            if(dis[i] + 1 == dis[dot[j]]) ++ in[dot[j]];
    for(int i = 1; i <= m; ++ i)
        if(dis[u[i]] > dis[v[i]]) swap(u[i], v[i]);
    while(Q --) {
        scanf("%d", &goal);
        if(dis[u[goal]] + 1 == dis[v[goal]]) del();
        printf("%d\n", ans);
    }
    return 0;
}
posted on 2020-05-06 15:13  Oxide  阅读(190)  评论(0编辑  收藏  举报