题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5361
题意:
给出n个点可以到达的点的距离差范围(l,r),和每个点的点值。n个点的位置分别为(0,1,2,3...n).
从0点出发,求出到达其他各点的最小花费,如果无法达到则输出“-1”。
思路:
dijkstra的思路,在每个点只可能标记一次最短路,所以使用一个set去记录所有点,标记了最短路的点删去。
将一个集合的点看成一个点,用一个set(可以用优先队列去实现) 去储存。取出这个点,将枚举这个点能够到达的点,更新dis,和在上一个set删点。
AC.
#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>
#include <cstring>
#include <cmath>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
set<int> fir;
struct node{
int id;
ll val;
node(int ii, ll vv) {
id = ii; val = vv;
}
bool operator < (const node &b) const {
if(val == b.val) return id < b.id;
return val < b.val;
}
};
set<node> nex;
int l[maxn], r[maxn];
ll val[maxn];
ll dis[maxn];
int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
scanf("%d", &l[i]);
}
for(int i = 0; i < n; ++i) {
scanf("%d", &r[i]);
}
for(int i = 0; i < n; ++i) {
scanf("%I64d", &val[i]);
}
fir.clear();
nex.clear();
memset(dis, -1, sizeof(dis));
dis[0] = 0;
for(int i = 1; i < n; ++i) {
fir.insert(i);
}
nex.insert(node(0, val[0]));
set<int>::iterator it, tmp;
while(!nex.empty()) {
node x = *nex.begin();
nex.erase(nex.begin());
int id = x.id;
it = fir.lower_bound(id - r[id]);
while(it != fir.end() && *it <= (id-l[id])) {
dis[*it] = x.val;
//printf("id = %d, it = %d, dis = %d\n", id, *it, dis[*it]);
nex.insert(node(*it, dis[*it]+val[*it]));
tmp = it++;
fir.erase(tmp);
}
it = fir.lower_bound(id+l[id]);
while(it != fir.end() && *it <= (id+r[id])) {
dis[*it] = x.val;
//printf("id = %d, it = %d, dis = %d\n", id, *it, dis[*it]);
nex.insert(node(*it, dis[*it]+val[*it]));
tmp = it++;
fir.erase(tmp);
}
}
for(int i = 0; i < n; ++i) {
printf("%I64d", dis[i]);
if(i < n-1) printf(" ");
else printf("\n");
}
}
return 0;
}