【题目链接】
【思路要点】
- 按照每条边的 q i q_i qi 排序,则显然有 O ( M 2 ) O(M^2) O(M2) 的动态规划做法。
- 将每一条边看做两个事件,一个在 p i p_i pi 时刻的询问 d p dp dp 值的事件和一个在 q i q_i qi 时刻的插入 d p dp dp 值的事件,则我们只需要快速进行转移。
- 注意到代价函数时关于时间距离的二次函数,且各项系数均非负,转移显然满足决策单调性,直接用决策单调性优化即可。
- 时间复杂度 O ( M L o g M ) O(MLogM) O(MLogM) 。
【代码】
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 2e5 + 5; const int MAXV = 1e3; const long long INF = 4e9; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } ll A, B, C; ll func(int x) { return A * x * x + B * x + C; } struct info {int x, y, s, t; } a[MAXN]; struct pinfo {int home, l, r; } q[MAXN]; struct event {bool type; int when, home; } b[MAXN * 2]; ll dp[MAXN]; int n, m, tot; int cnt[MAXN], ql[MAXN], qr[MAXN]; bool cmp(info a, info b) {return a.t < b.t; } bool cnp(event a, event b) { if (a.when == b.when) return a.type > b.type; else return a.when < b.when; } ll trans(int from, int when) { return dp[from] + func(when - a[from].t); } int main() { freopen("route.in", "r", stdin); freopen("route.out", "w", stdout); read(n), read(m), read(A), read(B), B++, read(C); cnt[1]++, dp[0] = 0; for (int i = 1; i <= m; i++) { read(a[i].x), read(a[i].y); read(a[i].s), read(a[i].t); cnt[a[i].y]++; } sort(a + 1, a + m + 1, cmp); for (int i = 1; i <= n; i++) { ql[i] = cnt[i - 1] + 1; qr[i] = cnt[i - 1]; cnt[i] += cnt[i - 1]; } for (int i = 1; i <= m; i++) { b[++tot] = (event) {false, a[i].s, i}; b[++tot] = (event) {true, a[i].t, i}; } sort(b + 1, b + tot + 1, cnp); q[++qr[1]] = (pinfo) {0, 0, MAXV}; for (int i = 1; i <= tot; i++) { int timer = b[i].when, home = b[i].home; if (!b[i].type) { int pos = a[home].x; while (ql[pos] <= qr[pos] && timer > q[ql[pos]].r) ql[pos]++; if (ql[pos] <= qr[pos]) { chkmax(q[ql[pos]].l, timer); dp[home] = trans(q[ql[pos]].home, timer) + a[home].t - a[home].s; } else dp[home] = INF; } else { int pos = a[home].y; while (ql[pos] <= qr[pos] && timer > q[ql[pos]].r) ql[pos]++; if (ql[pos] <= qr[pos]) chkmax(q[ql[pos]].l, timer); while (ql[pos] <= qr[pos] && trans(home, q[qr[pos]].l) <= trans(q[qr[pos]].home, q[qr[pos]].l)) qr[pos]--; if (ql[pos] > qr[pos]) q[++qr[pos]] = (pinfo) {home, timer, MAXV}; else if (trans(home, MAXV) >= trans(q[qr[pos]].home, MAXV)) q[qr[pos]].r = MAXV; else { int l = q[qr[pos]].l, r = MAXV; while (l < r) { int mid = (l + r) / 2; if (trans(home, mid) <= trans(q[qr[pos]].home, mid)) r = mid; else l = mid + 1; } q[qr[pos]].r = l - 1; q[++qr[pos]] = (pinfo) {home, l, MAXV}; } } } ll ans = INF; for (int i = 1; i <= m; i++) if (a[i].y == n) chkmin(ans, dp[i]); cout << ans << endl; return 0; }