码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5361 In Touch (2015 多校6 1009)

时间:2015-08-07 11:05:53      阅读:113      评论:0      收藏:0      [点我收藏+]

标签:dijkstra   线段树   区间更新   优先队列   

题目: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("\n");
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 5361 In Touch (2015 多校6 1009)

标签:dijkstra   线段树   区间更新   优先队列   

原文地址:http://blog.csdn.net/u014357885/article/details/47336021

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!