CF1715E Long Way Home
tangtangpeng · · 题解
题意
给定一张
思路
最短路和斜率优化
考虑设计状态,
显然当
考虑如何转移
第一维完全可以不要,优化空间复杂度:
然后讨论最后一次行动是在边上走的情况,跑一遍最短路即可。
但是这样转移的时间复杂度是
考虑用斜率优化的方式快速求出决策点
转化为一次函数
对应形成的点的坐标就是
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1E5 + 10;
int n, m, k;
int f[N], g[N], ans[N];
bool vis[N];
struct Edge
{
int nxt, to, val;
}G[N * 4];
int head[N], cnt;
void add(int u, int v, int w)
{
G[++cnt].nxt = head[u];
G[cnt].to = v;
G[cnt].val = w;
head[u] = cnt;
}
void spfa()
{
queue<int> Q;
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
Q.push(i);
vis[i] = 1;
}
while(!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = 0;
for(int i = head[u]; i; i = G[i].nxt)
{
int v = G[i].to;
if(f[v] > f[u] + G[i].val)
{
f[v] = f[u] + G[i].val;
if(!vis[v])
{
Q.push(v);
vis[v] = 1;
}
}
}
}
}
int X(int j){return j;}
int Y(int j){return g[j] + j * j;}
double slope(int i, int j){return (X(i) - X(j)) ? (double)(Y(i) - Y(j)) / (double)(X(i) - X(j)) : 2100000000;}
signed main()
{
memset(ans, 0x3f, sizeof(ans));
cin >> n >> m >> k;
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
memset(f, 0x3f, sizeof(f));
f[1] = 0;
spfa();
while(k--)
{
int Q[N];
int h = 1, t = 0;
memset(Q, 0, sizeof(Q));
memcpy(g, f, sizeof(g));
for(int i = 1; i <= n; i++)
{
while(h < t && slope(Q[t - 1], Q[t]) >= slope(Q[t], i))
t--;
Q[++t] = i;
}
for(int i = 1; i <= n; i++)
{
while(h < t && slope(Q[h], Q[h + 1]) <= (double)i * 2.0)
h++;
f[i] = g[Q[h]] + (i - Q[h]) * (i - Q[h]);
}
spfa();
for(int i = 1; i <= n; i++)
ans[i] = min(ans[i], f[i]);
}
for(int i = 1; i <= n; i++)
cout << ans[i] << " ";
return 0;
}