\(\sf Description\)
\(\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;
}