NKOJ 3844 服务器信息储存(最短路)

P3844服务器信息储存

问题描述

 Byteland王国准备在各服务器间建立大型网络并提供多种服务。

网络由n台服务器组成,用双向的线连接。两台服务器之间最多只能有一条线直接连接,同时,每台服务器最多只能和10台服务器直接连接,但是任意两台服务器间必然存在一条路径将它们连接在一起。每条传输线都有一个固定传输的速度。δ(V, W)表示服务器V和W之间的最短路径长度,且对任意的V有δ(V, V)=0。

有些服务器比别的服务器提供更多的服务,它们的重要程度要高一些。我们用r(V)表示服务器V的重要程度(rank)。rank越高的服务器越重要。

每台服务器都会存储它附近的服务器的信息。当然,不是所有服务器的信息都存,只有感兴趣的服务器信息才会被存储。服务器V对服务器W感兴趣是指,不存在服务器U满足,r(U)>r(W)且δ(V, U)<=δ(V, W)。

举个例子来说,所有具有最高rank的服务器都会被别的服务器感兴趣。如果V是一台具有最高rank的服务器,由于δ(V, V)=0,所以V只对具有最高rank的服务器感兴趣。我们定义B(V)为V感兴趣的服务器的集合。

我们希望计算所有服务器储存的信息量,即所有服务器的|B(V)|之和。Byteland王国并不希望存储大量的数据,所以所有服务器存储的数据量(|B(V)|之和)不会超过30n。

你的任务是写一个程序,读入Byteland王国的网络分布,计算所有服务器存储的数据量。

输入格式

第一行两个整数n和m,(1≤n≤30000,1≤m≤5n)。n表示服务器的数量,m表示传输线的数量。

接下来n行,每行一个整数,第i行的整数为r(i)(1≤r(i)≤10),表示第i台服务器的rank。

接下来m行,每行表示各条传输线的信息,包含三个整数a,b,t(1≤t≤1000,1≤a,b≤n,a≠b)。a和b是传榆线所连接的两台服务器的编号,t是传输线的长度。

输出格式

一个整数,表示所有服务器存储的数据总量,即|B(V)|之和。

样例输入

4 3
2
3
1
1
1 4 30
2 3 20
3 4 20

样例输出

9

提示

样例解释

B(1)={1,2},B(2)={2},B(3)={2,3},B(4)={1,2,3,4}。

数据范围

对于 30%的数据,n≤100,m<=300。

对于 60%的数据,n≤1000,m<=20000。

对于 100%的数据, 1≤n≤30000,1≤m≤5n


首先预处理出$dis[i][k]$表示$i$号点所有到$rank=k$的点的距离的最小值。实现方式是在dijkstra时向堆中添加所有$rank=k$的点作为起点。

然后处理出$mindis[i][k]$表示$i$号点到所有$rank>=k$的点的距离的最小值。

最后枚举点$i$,跑一次dijkstra,算出有那些点对$i$号点感兴趣,如果一个点$x$出堆时,它和$i$的距离小于$mindis[x][rank[i]]$那么说明不存在rank大于$i$的点和$x$的距离小于等于$dis(x,i)$,因此$x$对$i$感兴趣。反之如果$dis(x,i)$大于等于$mindis[x][rank[i]]$,那么从$x$点再拓展出的点一定不可能对$i$感兴趣。因为假设从$x$经过一条长度为$k$的边到达$y$,那么$dis(y,i)=dis(x,i)+k$,而$$mindis[y][rank[i]]<=mindis[x][rank[i]]+k<=dis(x,i)+k=dis(y,i)$$
所以我们可以不从$x$点拓展新的节点,即$continue$


代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define min(a,b) ((a<b)?(a):(b))
#define N 33333
#define M 333333
using namespace std;
struct node{int x,d;};
bool operator<(node a,node b)
{return a.d>b.d;}
priority_queue<node>Q;
int n,m,Rank[N],F[12],ans;
int TOT,LA[N],NE[M],EN[M],LE[M];
int dis[N][12],Dis[N],mark[N],mindis[N][12];
void Dijkstra(int s)
{
int i,x,y,d;
node tmp,temp;
for(i=1;i<=n;i++)
if(Rank[i]==s)
{
dis[i][s]=0;
tmp.x=i;tmp.d=0;
Q.push(tmp);
}
while(!Q.empty())
{
temp=Q.top();
Q.pop();
x=temp.x;
d=temp.d;
if(d!=dis[x][s])continue;
for(i=LA[x];i;i=NE[i])
{
y=EN[i];
if(dis[y][s]>LE[i]+d)
{
dis[y][s]=LE[i]+d;
tmp.x=y;tmp.d=dis[y][s];
Q.push(tmp);
}
}
}
}
void dijkstra(int s)
{
int i,x,y,d;
node tmp,temp;
Dis[s]=0;
mark[s]=s;
tmp.x=s;
tmp.d=0;
Q.push(tmp);
while(!Q.empty())
{
tmp=Q.top();
Q.pop();
x=tmp.x;
d=tmp.d;
if(Dis[x]!=d)continue;
if(d<mindis[x][Rank[s]])ans++;
else continue;
for(i=LA[x];i;i=NE[i])
{
y=EN[i];
if(mark[y]!=s||Dis[y]>LE[i]+d)
{
Dis[y]=LE[i]+d;
if(mark[y]!=s)mark[y]=s;
temp.d=Dis[y];
temp.x=y;
Q.push(temp);
}
}
}
}
void ADD(int x,int y,int z)
{
TOT++;
EN[TOT]=y;
LE[TOT]=z;
NE[TOT]=LA[x];
LA[x]=TOT;
}
int main()
{
int i,j,x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&Rank[i]),F[Rank[i]]++;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
ADD(x,y,z);ADD(y,x,z);
}
memset(dis,60,sizeof(dis));
for(i=1;i<=10;i++)if(F[i])Dijkstra(i);
for(i=1;i<=n;i++)
{
mindis[i][10]=1e9;
for(j=9;j>=1;j--)mindis[i][j]=min(mindis[i][j+1],dis[i][j+1]);
}
for(i=1;i<=n;i++)dijkstra(i);
cout<<ans;
}