题面
Sol
我们可以考虑每种
rank
r
a
n
k
的点
u
u
会被哪些点感兴趣
如果
dis[u][v]<
d
i
s
[
u
]
[
v
]
<
所有满足
rank
r
a
n
k
大于
rank[u]
r
a
n
k
[
u
]
的点到
v
v
的距离
那么一定对
u
u
感兴趣
我们可以先遍最短路,处理出每种
rank
r
a
n
k
的点到所有点的最短路
计
f[i][j]
f
[
i
]
[
j
]
表示满足
i≤rank
i
≤
r
a
n
k
的点到所有点的最短路
然后每次从一个点
u
u
出发,寻找对它感兴趣的点
如果发现
f[rank[u]+1][v]≤dis[u][v]
f
[
r
a
n
k
[
u
]
+
1
]
[
v
]
≤
d
i
s
[
u
]
[
v
]
那么
v
v
不对感兴趣,而且所有
v
v
能松弛到的点也都不会
那么可以,每次不满足要求了就不丢进队列
复杂度是 O(ans+10n) O ( a n s + 10 n ) 的,可以接受
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(3e4 + 5);
const int INF(1e9);
typedef long long ll;
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, m, rk[_], first[_], cnt, f[15][_], vis[_], ans, dis[_], use[_];
struct Edge{
int to, next, w;
} edge[_ * 10];
struct Data{
int u, d;
IL int operator <(RG Data A) const{
return d > A.d;
}
};
priority_queue <Data> Q;
queue <int> Deq;
IL void Add(RG int u, RG int v, RG int w){
edge[cnt] = (Edge){v, first[u], w}, first[u] = cnt++;
}
IL void Dijkstra(RG int p, RG int *dis){
for(RG int i = 1; i <= n; vis[i] = 0, ++i)
if(rk[i] == p) dis[i] = 0, Q.push((Data){i, 0});
else dis[i] = INF;
while(!Q.empty()){
RG Data x = Q.top(); Q.pop();
if(vis[x.u]) continue;
vis[x.u] = 1;
for(RG int e = first[x.u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(x.d + w < dis[v]) Q.push((Data){v, dis[v] = x.d + w});
}
}
}
IL int SPFA(RG int x){
RG int ret = 0;
for(RG int i = 1; i <= n; ++i) dis[i] = INF, use[i] = vis[i] = 0;
Deq.push(x), dis[x] = 0, vis[x] = 1;
while(!Deq.empty()){
RG int u = Deq.front(); Deq.pop();
if(!use[u]) use[u] = 1, ++ret;
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(dis[u] + w < dis[v]){
dis[v] = dis[u] + w;
if(!vis[v] && f[rk[x] + 1][v] > dis[v]) vis[v] = 1, Deq.push(v);
}
}
vis[u] = 0;
}
return ret;
}
int main(RG int argc, RG char* argv[]){
n = Input(), m = Input();
for(RG int i = 1; i <= n; ++i) rk[i] = Input(), first[i] = -1, f[11][i] = INF;
for(RG int i = 1; i <= m; ++i){
RG int u = Input(), v = Input(), w = Input();
Add(u, v, w), Add(v, u, w);
}
for(RG int i = 10; i; --i){
Dijkstra(i, f[i]);
for(RG int j = 1; j <= n; ++j) f[i][j] = min(f[i][j], f[i + 1][j]);
}
for(RG int i = 1; i <= n; ++i) ans += SPFA(i);
printf("%d\n", ans);
return 0;
}