多校省选模拟4
目前只会 A
A
题意
给你一个 \(n\) 个点 \(m\) 个图,然后你要从 \(S\) 走到 \(T\),然后,你可以使用一次能力,从 \(x\) 走到 \(y\),花费 \((x-y)^2\)。
题解
我们这题很简单,怎么做呢,我们考虑,算出来 \(S\) 到每个点的路径长度,然后算出来 \(T\) 到每个点的路径长度。
然后,我们的答案相当于是
\[\min(dis1[x]+x^2+dis2[y]+y^2-2xy) \]那么,我们可以,用类似于斜率优化的东西,我们把 \(dis1[x] + x ^ 2\) 记为 \(c(x)\)。
然后,我们的答案就是
\[\min_{1\le x \le N} {(c(x)+\min_{1\le y \le n}(dis2[y] + y ^ 2 - 2xy))} \]那么相当于是,我们每个决策点的坐标是 \((y,dis2[y]+y^2)\),然后每次的斜率递增为 \(2x\),先把下凸壳做出来,然后直接在上面扫就完了。
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::pair;
using std::priority_queue;
using std::vector;
template <typename T>
inline T min(const T &x, const T &y) {
return x < y ? x : y;
}
template <typename T>
inline T max(const T &x, const T &y) {
return x > y ? x : y;
}
const int MAXN = 2e5 + 10, MAXM = 4e5 + 10;
const double eps = 1e-8;
int N, M, S, T, U[MAXM], V[MAXM], W[MAXM], hd, tl, Q[MAXN];
long long dis[MAXN], F[MAXN], G[MAXN], ANS[MAXN];
bool vis[MAXN];
vector<pair<int, int>> e[MAXN];
void getdis(int x) {
for (int i = 1; i <= N; ++i) {
e[i].clear();
}
if (x == S) {
for (int i = 1; i <= M; ++i) {
e[U[i]].emplace_back(V[i], W[i]);
}
} else {
for (int i = 1; i <= M; ++i) {
e[V[i]].emplace_back(U[i], W[i]);
}
}
memset(vis, 0, sizeof vis);
memset(dis, 63, sizeof dis);
dis[x] = 0;
priority_queue<pair<long long, int>, vector<pair<long long, int>>, std::greater<pair<long long, int>>> Q;
Q.emplace(0, x);
while (Q.size()) {
int u = Q.top().second;
Q.pop();
if (vis[u]) {
continue;
}
vis[u] = 1;
for (auto &i : e[u]) {
if (dis[i.first] > dis[u] + i.second) {
Q.emplace(dis[i.first] = dis[u] + i.second, i.first);
}
}
}
return;
}
int main() {
freopen("graph.in", "r", stdin);
freopen("graph.out", "w", stdout);
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> N >> M >> S >> T;
for (int i = 1; i <= M; ++i) {
cin >> U[i] >> V[i] >> W[i];
}
getdis(S);
for (int i = 1; i <= N; ++i) {
F[i] = dis[i] + (long long)i * i;
}
getdis(T);
for (int i = 1; i <= N; ++i) {
G[i] = dis[i] + (long long)i * i;
}
hd = 1;
tl = 0;
for (int i = 1; i <= N; ++i) {
while (hd < tl && (G[i] - G[Q[tl]]) * 1.0 / (i - Q[tl]) <=
(G[Q[tl]] - G[Q[tl - 1]]) * 1.0 / (Q[tl] - Q[tl - 1]) + eps) {
tl--;
}
Q[++tl] = i;
}
for (int i = 1; i <= N; ++i) {
while (hd < tl && (G[Q[hd + 1]] - G[Q[hd]]) * 1.0 / (Q[hd + 1] - Q[hd]) <= i * 2 + eps) {
++hd;
}
ANS[i] = F[i] + G[Q[hd]] - (long long)2 * i * Q[hd];
}
long long ret = F[T] - (long long)T * T;
for (int i = 1; i <= N; ++i) {
ret = min(ret, ANS[i]);
}
cout << ret << '\n';
return 0;
}