https://nanti.jisuanke.com/t/41290
题干:
Firdaws and Fatinah are living in a country with nn cities, numbered from 11 to nn. Each city has a risk of kidnapping or robbery.
Firdaws's home locates in the city uu, and Fatinah's home locates in the city vv. Now you are asked to find the shortest path from the city uu to the city vv that does not pass through any other city with the risk of kidnapping or robbery higher than ww, a threshold given by Firdaws.
Input
The input contains several test cases, and the first line is a positive integer TTindicating the number of test cases which is up to 5050.
For each test case, the first line contains two integers n (1≤n≤200)n (1≤n≤200) which is the number of cities, and q (1≤q≤2×104)q (1≤q≤2×104) which is the number of queries that will be given. The second line contains nn integers r1,r2,⋯,rnr1,r2,⋯,rn indicating the risk of kidnapping or robbery in the city 11 to nn respectively. Each of the following nnlines contains nn integers, the jj-th one in the ii-th line of which, denoted by di,jdi,j, is the distance from the city ii to the city jj.
Each of the following qq lines gives an independent query with three integers u,vu,v and ww, which are described as above.
We guarantee that 1≤ri≤1051≤ri≤105, 1≤di,j≤105 (i≠j)1≤di,j≤105 (i≠j), di,i=0di,i=0 and di,j=dj,idi,j=dj,i. Besides, each query satisfies 1≤u,v≤n1≤u,v≤n and 1≤w≤1051≤w≤105.
Output
For each test case, output a line containing Case #x: at first, where x is the test case number starting from 11. Each of the following qq lines contains an integer indicating the length of the shortest path of the corresponding query.
Example
Input
1
3 6
1 2 3
0 1 3
1 0 1
3 1 0
1 1 1
1 2 1
1 3 1
1 1 2
1 2 2
1 3 2
Output
Case #1:
0
1
3
0
1
2
题目大意:
给你一个n个点的有向完全图,每个点有点权ri,有Q组 询问,每次询问给出三个参数u,v,w,要求u到v的最短路,且要求途径的点的点权不能超过w(也就是点的点权<=w),让你输出这个最短路的权值。(n<=200,w<=1e5,q<=2e4)
解题报告:
考虑到n只有200,考虑FLoyd。又因为给定的w虽然有2e4个(每一个询问可能都对应一个w),但是对应到n个点上,其实可以缩点缩成200个权值,再考虑Floyd的性质,是前i个点的前提下进行的,所以直接改一改点的编号顺序(按照r排序),然后离线搞一搞就行了。把更新均摊到n个点中。
这题的标解是对r排序后做三维的Floyd,相当于每个版本都记录下来了这样可以在线做,对于每个询问,直接二分查找下标,然后输出结果就行了。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
struct Node {int r,id;bool operator<(const Node & b)const {return r < b.r;}
} R[MAX];
struct Nodee {int st,ed,w,id;bool operator<(const Nodee & b)const {return w < b.w;}
} q[MAX];
int n,Q;
int d[222][222],ans[MAX];
int main()
{int T,iCase=0;cin>>T;while(T--) {scanf("%d%d",&n,&Q);for(int i = 1; i<=n; i++) scanf("%d",&R[i].r),R[i].id = i;for(int i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) scanf("%d",&d[i][j]);}for(int u,v,w,i = 1; i<=Q; i++) {scanf("%d%d%d",&q[i].st,&q[i].ed,&q[i].w);q[i].id = i;}sort(R+1,R+n+1);sort(q+1,q+Q+1);int cur = 1,curw = 0;for(int i = 1; i<=Q; i++) {while(cur <= n && q[i].w >= R[cur].r) {int k = R[cur].id;for(int i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) d[i][j] = min(d[i][j],d[i][k] + d[k][j]);}cur++;}ans[q[i].id] = d[q[i].st][q[i].ed];}printf("Case #%d:\n",++iCase);for(int i = 1; i<=Q; i++) printf("%d\n",ans[i]);}return 0 ;
}