2015多校第6场 HDU 5361 并查集,最短路
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5361
题意:有n个点1-n, 每个点到相邻点的距离是1,然后每个点可以通过花费c[i]的钱从i点走到距离i点大于等于l[i]并且小于等于r[i]的点,问从节点1到每个节点的最短距离是多少?不能到达的话,输出-1。
题解参考:http://blog.csdn.net/jtjy568805874/article/details/47341905
解法:这题的难点主要在于边的条数过多,不能像普通的最短路那样子跑。不过此题的特点在于对于每个点来说,从这个点出去能到的任何点这个过程的花费是相同的,都是cost[i]。于是假设到达该点的距离为dis[i]则从该点能到的任何点j的值都是dis[j]=min(dis[j],dis[i]+cost[i]);于是只要按照dis[i]+cost[i]排序,当前最先的第一个点能到的点的距离一定都是最近的,这些点在这之后都不会再被更新了。这样只要维护一个并查集压缩路径,或者维护一个set存可能还会被更新的点就好了。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 2e5+10; struct FastIO { static const int S = 1310720; int wpos; char wbuf[S]; FastIO() : wpos(0) {} inline int xchar() { static char buf[S]; static int len = 0, pos = 0; if(pos == len) pos = 0, len = fread(buf, 1, S, stdin); if(pos == len) exit(0); return buf[pos ++]; } inline unsigned long long xuint() { int c = xchar(); unsigned long long x = 0; while(c <= 32) c = xchar(); for(; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0'; return x; } inline long long xint() { long long s = 1; int c = xchar(), x = 0; while(c <= 32) c = xchar(); if(c == '-') s = -1, c = xchar(); for(; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0'; return x * s; } inline void xstring(char *s) { int c = xchar(); while(c <= 32) c = xchar(); for(; c > 32; c = xchar()) * s++ = c; *s = 0; } inline double xdouble() { bool sign = 0; char ch = xchar(); double x = 0; while(ch <= 32) ch = xchar(); if(ch == '-') sign = 1, ch = xchar(); for(; '0' <= ch && ch <= '9'; ch = xchar()) x = x * 10 + ch - '0'; if(ch == '.') { double tmp = 1; ch = xchar(); for(; ch >= '0' && ch <= '9'; ch = xchar()) tmp /= 10.0, x += tmp * (ch - '0'); } if(sign) x = -x; return x; } inline void wchar(int x) { if(wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0; wbuf[wpos ++] = x; } inline void wint(long long x) { if(x < 0) wchar('-'), x = -x; char s[24]; int n = 0; while(x || !n) s[n ++] = '0' + x % 10, x /= 10; while(n--) wchar(s[n]); } inline void wstring(const char *s) { while(*s) wchar(*s++); } inline void wdouble(double x, int y = 6) { static long long mul[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000LL, 100000000000LL, 1000000000000LL, 10000000000000LL, 100000000000000LL, 1000000000000000LL, 10000000000000000LL, 100000000000000000LL}; if(x < -1e-12) wchar('-'), x = -x; x *= mul[y]; long long x1 = (long long) floorl(x); if(x - floor(x) >= 0.5) ++x1; long long x2 = x1 / mul[y], x3 = x1 - x2 * mul[y]; wint(x2); if(y > 0) { wchar('.'); for(size_t i = 1; i < y && x3 * mul[i] < mul[y]; wchar('0'), ++i); wint(x3); } } ~FastIO() { if(wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0; } } io; LL n, T, d[maxn], l[maxn], r[maxn], c[maxn], fa[maxn], ans, sum; struct cmp{ bool operator ()(const LL &x, const LL &y) const{ return d[x]+c[x]>d[y]+c[y]; } }; namespace DSU{ int fa[maxn]; void init(){ for(int i=1; i<=n+1; i++) fa[i]=i; } int find_set(int x){ if(x == fa[x]) return x; else return fa[x] = find_set(fa[x]); } void union_set(int x, int y){ int fx = find_set(x), fy = find_set(y); if(fx != fy){ fa[fx] = fy; } } } using namespace DSU; void Dijstra(int x) { priority_queue<LL,vector<LL>,cmp>q; d[x] = 0; q.push(x); while(q.size()) { LL L,R,u = q.top(); q.pop(); L = u-r[u], R = u-l[u]; if(R>0){ for(LL j=max(L,1LL); ; j++){ j = find_set(j); if(j>min(R,n)) break; if(d[j] > d[u]+c[u]){ d[j] = d[u]+c[u]; q.push(j); } union_set(j,j+1); } } L = u+l[u], R = u+r[u]; if(L<=n){ for(LL j=L;;j++){ j = find_set(j); if(j>min(R,n)) break; if(d[j]>d[u]+c[u]){ d[j] = d[u]+c[u]; q.push(j); } union_set(j,j+1); } } } return; } int main() { int T; T = io.xint(); while(T--) { n = io.xint(); sum = 0; for(int i=1; i<=n; i++) l[i] = io.xint(); for(int i=1; i<=n; i++) r[i] = io.xint(); for(int i=1; i<=n; i++) c[i] = io.xint(), sum+=c[i]; init(); for(int i=1; i<=n; i++) d[i] = sum+1; Dijstra(1); for(int i=1; i<=n; i++){ if(d[i] == sum+1) d[i] = -1; if(i<n) printf("%lld ", d[i]); else printf("%lld\n", d[i]); } } return 0; }