HDU 5361 In Touch (2015 多校6 1009 最短路 + 區間更新)
阿新 • • 發佈:2018-12-24
題意:最短路,求源點到所有點的最短距離。但與普通最短路不同的是,給出的邊是某點到區間[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("\n");
}
return 0;
}