1 5 2 0 0 0 1 3 1 1 0 5 1 1 1 1 1
0 2 1 1 -1HintIf you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
这题的难点主要在于边的条数过多,不能像普通的最短路那样子跑。
不过此题的特点在于对于每个点来说,从这个点出去能到的任何点这个过程的花费是相同的,都是cost[i]
于是假设到达该点的距离为dis[i]则从该点能到的任何点j的值都是dis[j]=min(dis[j],dis[i]+cost[i]);
于是只要按照dis[i]+cost[i]排序,当前最先的第一个点能到的点的距离一定都是最近的,这些点在这之后都不会再被更新了。
这样只要维护一个并查集压缩路径,或者维护一个set存可能还会被更新的点就好了。
#pragma comment(linker, "/STACK:102400000,102400000") #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<cmath> #include<queue> #include<vector> #include<map> #include<set> #include<functional> using namespace std; typedef long long LL; const LL maxn = 200010; LL n, T, d[maxn], l[maxn], r[maxn], c[maxn], ans, sum, fa[maxn]; void read(LL &res) { char ch; while ((ch = getchar())<'0' || ch>'9'); res = ch - '0'; while ((ch = getchar()) >= '0'&&ch <= '9') res = res * 10 + ch - '0'; } void write(LL x) { if (x > 9) write(x / 10); putchar(x % 10 + '0'); } struct cmp { bool operator()(const LL &a, const LL &b) const { return d[a] + c[a] > d[b] + c[b]; } }; LL find(LL x) { if (fa[x] == x) return x; return fa[x] = find(fa[x]); } void merge(LL x, LL y) { x = find(x); y = find(y); if (x == y) return; fa[x] = y; } void find_dis(LL x) { d[x] = 0; priority_queue<LL, vector<LL>, cmp> p; p.push(x); while (!p.empty()) { LL q = p.top(), ll, rr; p.pop(); ll = q - r[q]; rr = q - l[q]; if (rr > 0) for (LL j = max(ll, (LL)1);; j++) { j = find(j); if (j > min(rr, n)) break; if (d[j]>d[q] + c[q]) { d[j] = d[q] + c[q]; p.push(j); } merge(j, j + 1); } ll = q + l[q]; rr = q + r[q]; if (ll <= n) for (LL j = ll;; j++) { j = find(j); if (j > min(rr, n)) break; if (d[j]>d[q] + c[q]) { d[j] = d[q] + c[q]; p.push(j); } merge(j, j + 1); } } } int main() { read(T); while (T--) { read(n); sum = 0; for (int i = 1; i <= n; i++) read(l[i]); for (int i = 1; i <= n; i++) read(r[i]); for (int i = 1; i <= n; i++) read(c[i]), sum += c[i]; for (int i = 1; i <= n; i++) d[i] = sum + 1; for (int i = 1; i <= n + 1; i++) fa[i] = i; find_dis(1); for (int i = 1; i <= n; i++) { if (i > 1) putchar(' '); if (d[i] == sum + 1) putchar('-'), putchar('1'); else write(d[i]); } putchar(10); } return 0; }