一道最短路好题。
首先明确一点,把一条边的边权变成2,等于删去这条边。因为变成2后最短路肯定不会经过这条边,就相当于删去这条边了。
所以题目变成了依次删去Q条边,求每一次删完边后有几个点的最短路变大了。
多做做题就会有这么个思维:删边不好办,然而逆向加边方便多了。所以30做法就是离线逆向加边,跑Q次dijkstra。时间复杂度(Qnlogn)。
正解是基于这个暴力的:想想dijkstra更新最短路的时候,如果成功从u更新了dis[v],那么前提一定是dis[u]已经是最短路。所以每一次我们可以不跑dijkstra,只用判断加的边(x, y)中,当前距离dis2[x]或是dis2[y]是否已经成为了最短路,如果是,就从这个点开始尝试更新他能走到的点的最短路(bfs, dfs都行,实测dfs更快)。然后如果到一个点的距离变成了最短路,ans--。
然后就是代码细节了:因为Q <= m,所以有一些边没删去,所以事先要加上,加边的时候不要每一次都判断dis2[x]或dis2[y]是否成为了最短路,而是在循环外面直接从1号节点更新,因为只有1号结点延伸出去的才可能成为最短路。而要是每一都判断dfs的话,虽然dfs会马上退出来,然而如果是一个菊花图的话,对于1号结点,每一次都遍历了很多条边,时间复杂度达到O(n2)。(这也就是我第7个点为啥一直TLE的原因……)
还有就是dis2实际上用一个bool数组就够,标记过就表示这个点已经成为了最短路,不用记录他的距离。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, m, q; 38 struct Edge 39 { 40 int nxt, to; 41 }e[maxn << 2]; 42 int head[maxn], ecnt; 43 void add(int x, int y) 44 { 45 e[++ecnt] = (Edge){head[x], y}; 46 head[x] = ecnt; 47 } 48 49 struct Node 50 { 51 int x, y; 52 }egs[maxn << 1]; 53 54 #define pr pair<int, int> 55 #define mp make_pair 56 bool in[maxn]; 57 int dis[maxn]; 58 void dijkstra(int s) 59 { 60 Mem(dis, 0x3f); 61 dis[s] = 0; 62 priority_queue<pr, vector<pr>, greater<pr> > q; 63 q.push(mp(dis[s], s)); 64 while(!q.empty()) 65 { 66 int now = q.top().second; q.pop(); 67 if(in[now]) continue; 68 in[now] = 1; 69 for(int i = head[now]; i != -1; i = e[i].nxt) 70 { 71 if(dis[e[i].to] > dis[now] + 1) 72 { 73 dis[e[i].to] = dis[now] + 1; 74 q.push(mp(dis[e[i].to], e[i].to)); 75 } 76 } 77 } 78 } 79 80 bool vis[maxn << 1]; 81 int a[maxn << 1], ans[maxn << 1], num; 82 83 void solve(int now, int d) 84 { 85 for(int i = head[now]; i != -1; i = e[i].nxt) 86 { 87 if(!vis[e[i].to] && d + 1 == dis[e[i].to]) 88 { 89 num--; 90 vis[e[i].to] = 1; 91 solve(e[i].to, d + 1); 92 } 93 } 94 } 95 96 int main() 97 { 98 Mem(head, -1); ecnt = -1; 99 n = read(); m = read(); q = read(); 100 for(rg int i = 1; i <= m; ++i) 101 { 102 egs[i].x = read(); egs[i].y = read(); 103 add(egs[i].x, egs[i].y); add(egs[i].y, egs[i].x); 104 } 105 dijkstra(1); 106 for(rg int i = 1; i <= q; ++i) a[i] = read(), vis[a[i]] = 1; 107 Mem(head, -1); ecnt = -1; 108 num = n - 1; 109 for(int i = 1; i <= m; ++i) if(!vis[i]) 110 { 111 int x = egs[i].x, y = egs[i].y; 112 add(x, y); add(y, x); 113 } 114 Mem(vis, 0); vis[1] = 1; 115 solve(1, 0); 116 for(rg int i = q; i; --i) 117 { 118 ans[i] = num; 119 int x = egs[a[i]].x, y = egs[a[i]].y; 120 add(x, y); add(y, x); 121 if(vis[x]) solve(x, dis[x]); 122 if(vis[y]) solve(y, dis[y]); 123 } 124 for(rg int i = 1; i <= q; ++i) write(ans[i]), enter; 125 return 0; 126 }