题目:http://acm.hdu.edu.cn/showproblem.php?pid=5361
题意:最短路。求源点到全部点的最短距离。但与普通最短路不同的是,给出的边是某点到区间[l,r]内随意点的距离。
输入一个n,代表n个点,输入n个l[i],输入n个r[i],输入n个c[i]。
对于i,表示i到区间[i - r[i]],i - l[i]]和区间[i + l[i],i + r[i]]内的随意点的距离为c[i]。
求1到各个点的最短距离。
思路:若建边跑最短路的话,由于边过多,所以不可行。
由于在最后的结果中。可能源点1到某段区间的最短路径都是一样的,所以能够在最短路的算法基础上利用线段树区间更新来维护源点1到区间的最短路径,最后仅仅须要查询区间就可以。线段树的每一个结点存该区间源点到该区间点的最短路的最大值和最小值。
所以叶子结点即是源点1到该点的最短路径。(思路来源队友)
代码:
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <string.h>
#include <math.h>
#include <queue>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const long long INF = 1e18;
const int N = 2e5 + 10;
struct Segment {
int l, r;
long long d;
Segment(int l = 0, int r = 0, long long d = 0) {
this -> l = l;
this -> r = r;
this -> d = d;
}
friend bool operator < (Segment a, Segment b) {
return a.d > b.d;
}
};
struct Node {
int used;//标记该段区间是否使用过。由于距离均为正值,所以若该区间已是最短距离,则不须要继续更新。
long long _max;
long long _min;
};
Node node[N << 2];
long long lazy[N << 2];
int n;
int lef[N];
int rig[N];
long long c[N];
priority_queue<Segment> q;
void pushup(int rt) {
node[rt]._max = max(node[rt << 1]._max, node[rt << 1 | 1]._max);
node[rt]._min = min(node[rt << 1]._min, node[rt << 1 | 1]._min);
if (node[rt << 1].used == node[rt << 1 | 1].used)
node[rt].used = node[rt << 1].used;
else
node[rt].used = -1;
}
void pushdown(int rt) {
if (lazy[rt] != -1) {
lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
node[rt << 1]._min = node[rt << 1]._max = lazy[rt];
node[rt << 1 | 1]._min = node[rt << 1 | 1]._max = lazy[rt];
lazy[rt] = -1;
}
}
void build(int l, int r, int rt) {
node[rt]._max = INF;
node[rt]._min = INF;
node[rt].used = 0;
lazy[rt] = -1;
if (l == r) {
if (l == 1) {
node[rt]._max = 0;
node[rt]._min = 0;
}
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
void update(long long cr, int L, int R, int l, int r, int rt) {
if (node[rt]._max <= cr)
return ;
if (L <= l && r <= R) {
node[rt]._max = cr;
if (node[rt]._min > cr) {
node[rt]._min = cr;
q.push(Segment(l, r, cr));
lazy[rt] = cr;
return ;
}
}
if (l == r)
return ;
pushdown(rt);
int m = (l + r) >> 1;
if (L <= m)
update(cr, L, R, lson);
if (R > m)
update(cr, L, R, rson);
pushup(rt);
}
void querysegment(Segment ff, int l, int r, int rt) {
if (node[rt].used == 1)
return ;
if (ff.l <= l && r <= ff.r) {
if (node[rt].used == 0) {
for (int i = l; i <= r; i++) {
int le = i + lef[i];
int ri = min(n, i + rig[i]);
if (le <= n) {
update(ff.d + c[i], le, ri, 1, n, 1);
}
le = max(1, i - rig[i]);
ri = i - lef[i];
if (ri >= 1) {
update(ff.d + c[i], le, ri, 1, n, 1);
}
}
node[rt].used = 1;
return ;
}
}
if (l == r)
return ;
int m = (l + r) >> 1;
if (ff.l <= m)
querysegment(ff, lson);
if (ff.r > m)
querysegment(ff, rson);
pushup(rt);
}
bool fir;
void query(int l, int r, int rt) {
if (node[rt]._max == node[rt]._min) {
for (int i = l; i <= r; i++) {
if (node[rt]._min == INF)
node[rt]._min = -1;
if (!fir) {
printf("%lld", node[rt]._min);
fir = true;
}
else
printf(" %lld", node[rt]._min);
}
return ;
}
if (l == r) {
return ;
}
pushdown(rt);
int m = (l + r) >> 1;
query(lson);
query(rson);
}
int main() {
int t_case;
scanf("%d", &t_case);
for (int i_case = 1; i_case <= t_case; i_case++) {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &lef[i]);
for (int i = 1; i <= n; i++)
scanf("%d", &rig[i]);
for (int i = 1; i <= n; i++)
scanf("%lld", &c[i]);
build(1, n, 1);
while(!q.empty())
q.pop();
q.push(Segment(1, 1, 0));
while (!q.empty()) {
Segment ff = q.top();
q.pop();
querysegment(ff, 1, n, 1);
}
fir = false;
query(1, n, 1);
printf("
");
}
return 0;
}