题目大意:
N个省M条路,然后每个省有一些城市,M条路连接着两座城市(保证是连通图),有什么省级优惠:连接一个省中的两个城市的路费得到xi%的优惠,连接两个省的路得到(xi% + xj%) / 2的优惠,还有什么国家级优惠,如果这个价格在L—R之间则免费,问L & R的大小
解题思路:
dfs + 二分嵌套
二分出 L & R,判断条件是满足(价格>=L && 价格<R)的情况下可以从S到T,满足则不断将L弄大,否则弄小
R同理
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i, a, b, c) for(register int i = a; b; i = c)
#define r(i, a, b) for (register int i = a; i <= b; i++)
#define f(i, a, b) for (register int i = a; i >= b; i--)
using namespace std;
struct SPFA {
int to, next;
double w;
}e[500001];
int cnt, N, M, last[200001], s, t;
int n, QWERTYUIOP, u[200001], v[200001], a[200001];
double w[200001], X[200001];//别管那个QWERTYUIOP
double pt(double x) { return x * 0.01; }//x%
inline void add(int u, int v, double w) {
e[++cnt].to = v; e[cnt].w = w;
e[cnt].next = last[u]; last[u] = cnt;
e[++cnt].to = u; e[cnt].w = w;
e[cnt].next = last[v]; last[v] = cnt;
}//双向边
bool dfs(int now, int low, int high) {
//dfs判断是否有一条路径上每一条路的路费都 low<= <high
if (now == t) return 1;//已经到了
if (v[now]) return 0;//走过就不走了
v[now] = 1;//标记
rep(i, last[now], i, e[i].next)//枚举边
if (e[i].w >= (double)low && e[i].w < (double)high)
//判断路费是否满足条件
if (dfs(e[i].to, low, high)) return 1;
//接着搜
return 0;
}
int main() {
scanf("%d%d", &N, &M);
r(i, 1, M) scanf("%d%d%lf", &u[i], &v[i], &w[i]);
r(i, 1, N) {
scanf("%d", &n);
r(j, 1, n)
scanf("%d", &QWERTYUIOP),
a[QWERTYUIOP] = i;
}
r(i, 1, N) scanf("%lf", &X[i]);
scanf("%d%d", &s, &t);
r(i, 1, M) {
double rz = 0;
if (a[u[i]] != a[v[i]])
rz = (pt(X[a[u[i]]]) + pt(X[a[v[i]]])) / 2.0 * (double)w[i];
else rz = pt((double)X[a[u[i]]]) * (double)w[i];
add(u[i], v[i], rz);//建图
}
int L = 0, R = 15000, L1 = 0, R1 = 0, mid1, mid2;
while (L <= R) {//二分
mid1 = (L + R) >> 1;
int l = mid1, r = 15000;
bool ok = 0;
memset(v, 0, sizeof(v));//初始化
if (dfs(s, mid1, 2e5)) {
while (l <= r) {//嵌套
memset(v, 0, sizeof(v));//初始化
mid2 = (l + r) >> 1;
if (dfs(s, mid1, mid2)) {//判断是否满足条件的路径
ok = 1;
L1 = mid1; R1 = mid2;//记录下答案
r = mid2 - 1;
} else l = mid2 + 1;
}
}
if (ok) L = mid1 + 1;
else R = mid1 - 1;//常规二分
}
printf("%d %d", L1, R1);
}