HDU 5361 In Touch (2015 多校6 1009 最短路 + 区间更新)

来源:互联网 发布:mac怎么取消隐藏文件 编辑:程序博客网 时间:2024/06/10 09:32

题目: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 | 1const 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;}
0 0
原创粉丝点击