题意
一张图,上面有些边可能为xxx,xxx不是一个固定的值。每次询问给出AAA和BBB,求出最短路不同的可能值的数目和它们的总和。如果不同的可能值的数目是无限的,该行只输出infinfinf。如果没有从AAA到BBB的路径,不同的可能值的数目及它们的总和都是000。
。
思路
先分层图跑出fif_ifi代表经过iii条xxx边的最短路。
对于第一问,判断一下求出的fff就好了。
对于第二问:
经过iii条xxx边代价为fi+i∗xf_i+i*xfi+i∗x
把y=fi+i∗xy=f_i+i*xy=fi+i∗x扔到坐标系,可以发现当xxx不同时,到最短路经过的xxx边数也不同,由于是最短路,所以我们在坐标系中对每个xxx取yyy最小的情况,发现是个上凸壳,单调栈维护一下,对凸壳中两个交点,答案贡献为f[i]+ix(xf[i]+ix(xf[i]+ix(x从一个点到另一个点))),用等差数列搞一搞。
代码
#include<queue>
#include<cstdio>
#include<cstring>
const int inf = 707406378;
int n, m, tot, s, t;
int dis[501][501], vis[501][501], stack[501];
int ver[10001], next[10001], edge[10001], head[501];
double p[501];
struct heap{
int u, dis, used;
};
bool operator <(const heap &a, const heap &b) {
return a.dis > b.dis;
}
int read() {
int res = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f *= -1;
if (ch == 'x') return 0;
ch = getchar();
}
while (ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0', ch = getchar();
return res;
}
void add(int u, int v, int w) {
ver[++tot] = v;
next[tot] = head[u];
edge[tot] = w;
head[u] = tot;
}
void dijkstra() {
std::priority_queue<heap> q;
memset(dis, 127 / 3, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s][0] = 0;
q.push((heap){s, 0, 0});
while (q.size()) {
int u = q.top().u, rk = q.top().used;
q.pop();
if (vis[u][rk]) continue;
vis[u][rk] = 1;
for (int i = head[u]; i; i = next[i]) {
int v = ver[i];
if (rk < n && !vis[v][rk + 1] && dis[v][rk + 1] > dis[u][rk] && !edge[i]) dis[v][rk + 1] = dis[u][rk], q.push((heap){v, dis[v][rk + 1], rk + 1});
if (!vis[v][rk] && dis[v][rk] > dis[u][rk] + edge[i] && edge[i]) dis[v][rk] = dis[u][rk] + edge[i], q.push((heap){v, dis[v][rk], rk});
}
}
}
double get(int x, int y) {
return (double)(dis[t][x] - dis[t][y]) / (y - x);
}
long long add(int k, int b, int l, int r) {
return (long long)(k * (l + r) + b * 2) * (r - l + 1) >> 1;
}
int main() {
n = read();
m = read();
for (int i = 1; i <= m; i++) {
int x = read(), y = read(), z = read();
add(x, y, z);
}
for (int q = read(); q; q--) {
s = read();
t = read();
dijkstra();
int flag = 0;
for (int i = 0; i <= n; i++)
if (dis[t][i] != inf) {
flag = 1;
break;
}
if (!flag) {
printf("0 0\n");
continue;
}
if (dis[t][0] == inf) {
printf("inf\n");
continue;
}
int top = 0;
for (int i = n; i >= 0; i--) {
if (dis[t][i] == inf) continue;
while (top && p[top] >= get(stack[top], i)) top--;
if (top) p[top + 1] = get(stack[top], i);
stack[++top] = i;
}
int sum = p[top];
long long ans = 0;
for (int i = 1; i < top; i++) ans += add(stack[i], dis[t][stack[i]], (int)p[i] + 1, (int)p[i + 1]);
if (sum * stack[top - 1] + dis[t][stack[top - 1]] != dis[t][0] || top == 1) ans += dis[t][0], sum++;
printf("%d %lld\n", sum, ans);
}
}

415

被折叠的 条评论
为什么被折叠?



