CF786B Legacy 线段树优化Dijkstra

一.题目

传送门
翻译:

二.题解

如果这道题目没有后面两个操作,那么就是一个Dijkstra跑过,但是当加上后两个操作,如果 v v v向每个区间内的点连一条边将会连 n 2 n^2 n2条边,存不下也跑不过。
这时就得使用线段树来优化Dijkstra。
我们不如直接将点 v v v连到区间 l − r l-r lr上或将区间 l − r l-r lr连到点 v v v上,具体操作下面我将线段树的打法解释一下:

首先要建两颗线段树 t r e e i n [ I n d e x ] , t r e e o u t [ I n d e x ] treein[Index],treeout[Index] treein[Index],treeout[Index]分别代表外面的点连到区间和区间连向外部的点,建树的时候在每棵树内建边, t r e e i n [ I n d e x ] treein[Index] treein[Index]这棵树就是从父亲向儿子连边而 t r e e o u t [ I n d e x ] treeout[Index] treeout[Index]这棵树就是儿子向父亲连边,然后每次更新,就直接将点连到完全被 l − r l-r lr包含在内的线段树区间内,或反着连,线段树每个区间的编号从 n + 1 n + 1 n+1开始,注意跑Dijkstra时要将线段树的所有区间带着一起跑。注意不要炸空间

三.Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstdlib>
using namespace std;

#define M 100005
#define LL long long
const LL INF = 1e15;

struct node {
    int v; LL Dis;
    node (){};
    node (int V, LL DIS){
        v = V;
        Dis = DIS;
    }
    bool operator < (const node& rhs) const{
        return rhs.Dis < Dis;
    }
};
int n, q, s, treein[M * 4], treeout[M * 4], cnt;
LL dis[M];
vector <pair <int, LL> > G[M * 8];
priority_queue <node> Q;

void build (int Index, int l, int r){
    if (l == r){
        treein[Index] = treeout[Index] = l;
        return ;
    }
    int mid = l + r >> 1;
    build (Index << 1, l, mid);
    build ((Index << 1) | 1, mid + 1, r);
    treein[Index] = ++ cnt;
    treeout[Index] = ++ cnt;
    G[treein[Index]].push_back (make_pair (treein[Index * 2], 0));
    G[treein[Index]].push_back (make_pair (treein[Index * 2 + 1], 0));
    G[treeout[Index * 2]].push_back (make_pair (treeout[Index], 0));
    G[treeout[Index * 2 + 1]].push_back (make_pair (treeout[Index], 0));
}
void updatein (int Index, int l, int r, int L, int R, int from, LL val){
    if (L <= l && R >= r){
        G[from].push_back (make_pair (treein[Index], val));
        return ;
    }
    int mid = (l + r) >> 1;
    if (L <= mid)
        updatein (Index * 2, l, mid, L, R, from, val);
    if (R > mid)
        updatein (Index * 2 + 1, mid + 1, r, L, R, from, val);
}
void updateout (int Index, int l, int r, int L, int R, int from, LL val){
    if (L <= l && R >= r){
        G[treeout[Index]].push_back (make_pair (from, val));
        return ;
    }
    int mid = l + r >> 1;
    if (L <= mid)
        updateout (Index * 2, l, mid, L, R, from, val);
    if (R > mid)
        updateout (Index * 2 + 1, mid + 1, r, L, R, from, val);
}
void Dijkstra (){
    for (int i = 1; i <= cnt; i ++)
        dis[i] = INF;
    dis[s] = 0;
    Q.push (node (s, 0));
    while (! Q.empty ()){
        node now = Q.top ();
        Q.pop ();
        if (now.Dis != dis[now.v])
            continue;
        for (int i = 0; i < G[now.v].size(); i ++){
            int tmp = G[now.v][i].first; LL tot = G[now.v][i].second;
            if (dis[tmp] > now.Dis + tot){
                dis[tmp] = now.Dis + tot;
                Q.push (node (tmp, dis[tmp]));
            }
        }
    }
}
int main (){
    scanf ("%d %d %d", &n, &q, &s);
    cnt = n;
    build (1, 1, n);
    while (q --){
        int flag, v, l, r; LL w;
        scanf ("%d", &flag);
        if (flag == 1){
            scanf ("%d %d %lld", &v, &l, &w);
            G[v].push_back (make_pair (l, w));
        }
        if (flag == 2){
            scanf ("%d %d %d %lld", &v, &l, &r, &w);
            updatein (1, 1, n, l, r, v, w);
        }
        if (flag == 3){
            scanf ("%d %d %d %lld", &v, &l, &r, &w);
            updateout (1, 1, n, l, r, v, w);
        }
    }
    Dijkstra ();
    for (int i = 1; i <= n; i ++){
        if (dis[i] == INF)
            printf ("-1 ");
        else
            printf ("%lld ", dis[i]);
    }
    return 0;
}

Thanks !

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值