Description
Air Bovinia operates flights connecting the N farms that the cows live on (1 <= N <= 20,000). As with any airline, K of these farms have been designated as hubs (1 <= K <= 200, K <= N).
Currently, Air Bovinia offers M one-way flights (1 <= M <= 20,000), where flight i travels from farm u_i to farm v_i and costs d_i (1 <= d_i <= 10,000) dollars. As with any other sensible airline, for each of these flights, at least one of u_i and v_i is a hub. There is at most one direct flight between two farms in any given direction, and no flight starts and ends at the same farm.
Bessie is in charge of running the ticketing services for Air Bovinia. Unfortunately, while she was away chewing on delicious hay for a few hours, Q one-way travel requests for the cows' holiday vacations were received (1 <= Q <= 50,000), where the ith request is from farm a_i to farm b_i.
As Bessie is overwhelmed with the task of processing these tickets, please help her compute whether each ticket request can be fullfilled, and its minimum cost if it can be done.
To reduce the output size, you should only output the total number of ticket requests that are possible, and the minimum total cost for them. Note that this number might not fit into a 32-bit integer.
是n个点m条有向边,求两两之间的最短路,要求路径上必须经过编号1~k的至少一个点
Input
Line 1: The integers N, M, K, and Q.
Lines 2..M + 1: Line i+1 contains u_i, v_i, and d_i. (1 <= u_i, v_i <= N, u_i != v_i)
Lines M + 2..M + K + 1: Each of these lines contains the ID of a single hub (in the range 1..N).
- Lines M + K + 2..M + K + Q + 1: Two numbers per line, indicating a request for a ticket from farm a_i to b_i. (1 <= a_i, b_i <= N, a_i != b_i)
Output
Line 1: The number of ticket requests that can be fullfilled.
- Line 2: The minimum total cost of fulling the possible ticket requests
Sample Input
3 3 1 2
1 2 10
2 3 10
2 1 5
2
1 3
3 1
Sample Output
1
20
Hint
For the first flight, the only feasible route is 1->2->3, costing 20. There are no flights leaving farm 3, so the poor cows are stranded there.
题解
显然是一道求多源最短路的题,而总的点数远远超过了$floyd$的承受范围。
我们用分治的思想,注意到题中所有边都是与“关键点”即收费站相连的,显然我们可以考虑对于这些点进行$floyd$。
对于非关键点的点,我们可以枚举,并在之前$floyd$处理完的“块”内求一遍单源最短路,注意与枚举的点相连的边是“出边”还是“入边”。
处理答案时,注意点要分是在“块”内还是“块”外。
#include<cmath>
#include<queue>
#include<ctime>
#include<stack>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N=;
int INF; struct tt
{
int to,next,cost;
}edge[N+];
int path[N+],top;
int n,m,k,q,u,v,d;
int x[],num[N+];
int map[][];
int in[N+][],out[][N+]; void Count_in();
void Count_out();
void Floyd();
void Build();
inline void Add(int x,int y,int c);
inline int my_min(int x,int y);
inline int Read(); int main()
{
n=Read();m=Read();k=Read();q=Read();
for (int i=;i<=m;i++)
{
u=Read();v=Read();d=Read();
Add(u,v,d);
}
for (int i=;i<=k;i++)
{
x[i]=Read();
num[x[i]]=i;
}
Floyd();
Count_in();
Count_out();
int cnt=,sum=,ans=*INF,x,y;
for (int i=;i<=q;i++)
{
x=Read();y=Read();
if (num[x]&&num[y]) {if (map[num[x]][num[y]]<INF) cnt++,sum+=map[num[x]][num[y]];}
else if (num[x]) {if (out[num[x]][y]<INF) cnt++,sum+=out[num[x]][y];}
else if (num[y]) {if (in[x][num[y]]<INF) cnt++,sum+=in[x][num[y]];}
else
{
int ans=*INF;
for (int j=;j<=k;j++) if (in[x][j]+out[j][y]<ans) ans=in[x][j]+out[j][y];
if (ans<INF) cnt++,sum+=ans;
}
}
printf("%d\n%d\n",cnt,sum);
return ;
} inline void Add(int x,int y,int c)
{
edge[++top].to=y;
edge[top].cost=c;
edge[top].next=path[x];
path[x]=top;
}
void Floyd()
{
memset(map,/,sizeof(map));
Build();
for (int p=;p<=k;p++)
for (int i=;i<=k;i++)
for (int j=;j<=k;j++)
if (map[i][j]>map[i][p]+map[p][j])
map[i][j]=map[i][p]+map[p][j];
}
void Build()
{
for (int i=;i<=k;i++)
for (int j=path[x[i]];j;j=edge[j].next)
if (!num[edge[j].to])
for (int p=path[edge[j].to];p;p=edge[p].next)
map[i][num[edge[p].to]]=my_min(map[i][num[edge[p].to]],edge[j].cost+edge[p].cost);
else map[i][num[edge[j].to]]=my_min(map[i][num[edge[j].to]],edge[j].cost);
}
void Count_in()
{
memset(in,/,sizeof(in));INF=in[][];
for (int i=;i<=n;i++) if (!num[i])
{
for (int j=path[i];j;j=edge[j].next)
{
if (in[i][num[edge[j].to]]>edge[j].cost)
in[i][num[edge[j].to]]=edge[j].cost;
for (int p=;p<=k;p++) if (in[i][p]>map[num[edge[j].to]][p]+edge[j].cost)
in[i][p]=map[num[edge[j].to]][p]+edge[j].cost;
}
}
}
void Count_out()
{
memset(out,/,sizeof(out));
for (int i=;i<=k;i++)
{
for (int j=path[x[i]];j;j=edge[j].next) if (!num[edge[j].to])
{
if (out[i][edge[j].to]>edge[j].cost)
out[i][edge[j].to]=edge[j].cost;
for (int p=;p<=k;p++) if (out[p][edge[j].to]>map[p][i]+edge[j].cost)
out[p][edge[j].to]=map[p][i]+edge[j].cost;
}
}
}
inline int my_min(int x,int y) {return x<y ? x:y;}
inline int Read()
{
int sum=;
char ch=getchar();
while (ch<''||ch>'') ch=getchar();
while (ch>=''&&ch<='')
{
sum=sum*+ch-'';
ch=getchar();
}
return sum;
}