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


代码:

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值