HDU - 5669 Road 【线段树优化建图 and 思维类dp最短路】

传送门
题意: q次描述, 每次描述给出两个区间 a b 和 c d, 表示这里存在一条路在节点 (x,y)之间 ,a ≤ x ≤ b,c ≤ y ≤ d. 权值给出, 问1到n的最短路是多少, 其中你可以使用不超过k次的技能, 每使用一次, 那么你使用的那条道路的权值可以不进行累加, 即该条道路权值为零.

思路: 这道题很明显的线段树优化建图了, 具体建图方法可以参照我另一篇博客 一样的建, 唯一不同的是这次是区间到区间, 那么没事, 我们分开两次在入树和出树上找对应区间编号即可.
那么图建好了, 怎么求最短路, 有个k的限制, 所以我们可以类dp思考, dp[i][j] 代表走到j这个点使用i次技能, 那么我们在最短路更新时多加一个判断条件即可, 即是否这个可以使用技能并使用掉, 然后更新. 还是比较简单的….

最后在dis[0-k][n]中输出最小的答案即可.
注意范围, 不要手残, 我因为判断时该写k写成了n,re了一个多小时… 吐血…

AC Code

const int maxn = 5e5 + 5;
const int maxm = 4e6 + 5;
struct node {
    int to, next, w, ti;
    bool operator < (const node &_) const {
        return w > _.w;
    }
}e[maxm];
int n, q, k, idx;
int head[maxn], cnt;
struct Tree {
    int tl, tr, val;
}tree[2][maxn];
void init() {
    Fill(head, -1); cnt = 0;
    Fill(tree, 0); idx = n;
}
void add(int u, int v, int w) {
    e[cnt] = node{v, head[u], w, 0};
    head[u] = cnt++;
}
void build(int id, int l, int r, int f) {
    tree[f][id].val = ++idx;
    tree[f][id].tl = l, tree[f][id].tr = r;
    if (l == r) {
        if (!f) add(idx, l, 0);
        else add(l, idx, 0);
        return ;
    }
    int mid = (l + r) >> 1;
    build(id<<1, l, mid, f);
    build(id<<1|1, mid+1, r, f);
    if (!f) {
        add(tree[f][id].val, tree[f][id<<1].val, 0);
        add(tree[f][id].val, tree[f][id<<1|1].val, 0);
    }
    else {
        add(tree[f][id<<1].val, tree[f][id].val, 0);
        add(tree[f][id<<1|1].val, tree[f][id].val, 0);
    }
}
vector<int>vs[2];
void query(int id, int ql, int qr, int f) {
    int l = tree[f][id].tl, r = tree[f][id].tr;
    if (ql <= l && r <= qr) {
        vs[f].pb(tree[f][id].val);
        return ;
    }
    int mid = (l + r) >> 1;
    if (qr <= mid) query(id<<1, ql, qr,f );
    else if (ql > mid) query(id<<1|1, ql, qr, f);
    else {
        query(id<<1, ql, mid, f);
        query(id<<1|1, mid+1, qr, f);
    }
}
int dis[12][maxn]; bool vis[12][maxn];
void dij(int st,int ed) {
    priority_queue<node> q;
    Fill(dis, inf); Fill(vis, false);
    dis[0][st] = 0;
    q.push(node{st, 0, 0, 0});
    while (!q.empty()) {
        node u = q.top();
        q.pop();
        if(vis[u.ti][u.to]) continue;
        vis[u.ti][u.to] = 1;  

        for (int i = head[u.to]; ~i; i = e[i].next) {
            int to = e[i].to;
            if (dis[u.ti][to] > dis[u.ti][u.to] + e[i].w) {
                dis[u.ti][to] = dis[u.ti][u.to] + e[i].w;
                q.push(node{to, 0, dis[u.ti][to], u.ti});
            }
            if (u.ti < k && dis[u.ti+1][to] > dis[u.ti][u.to]) {
                dis[u.ti+1][to] = dis[u.ti][u.to];
                q.push(node{to, 0, dis[u.ti+1][to], u.ti+1});
            }
        }
    }
    int ans = inf;
    for (int i = 0 ; i <= k ; i ++) {
        ans = min(ans, dis[i][ed]);
    }
    if (ans == inf) puts("CreationAugust is a sb!");
    else printf("%d\n", ans);
}
void solve() {
    scanf("%d%d%d", &n, &q, &k);
    init();
    build(1, 1, n, 0);
    build(1, 1, n, 1);
    while(q--) {
        int a, b, c, d, w;
        scanf("%d%d%d%d%d", &a, &b, &c, &d, &w);
        vs[0].clear(); vs[1].clear();
        query(1, a, b, 0); query(1, c, d, 1);
        for (int i = 0 ; i < sz(vs[1]) ; i ++) {
            for (int j = 0 ; j < sz(vs[0]) ; j ++) {
                add(vs[1][i], vs[0][j], w);
            }
        }
        vs[0].clear(); vs[1].clear();
        query(1, c, d, 0); query(1, a, b, 1);
        for (int i = 0 ; i < sz(vs[1]) ; i ++) {
            for (int j = 0 ; j < sz(vs[0]) ; j ++) {
                add(vs[1][i], vs[0][j], w);
            }
        }
    }
    dij(1, n);
}

猜你喜欢

转载自blog.csdn.net/anxdada/article/details/80433365
今日推荐