CodeForces-786B Legacy (线段树优化建图,单源最短路)

题目链接:CodeForces-786B  Legacy

题意

有$n$个点,$q$次3种类型的操作:

$1\ u\ v\ w$,连边$u\to v$,权值为$w$;
$2\ v\ l\ r\ w$,连边$v\to [l, r]$,权值为$w$;
$3\ v\ l\ r\ w$,连边$[l,r]\to v$,权值为$w$。

其中$[l,r]$表示结点编号在此范围内的所有结点。

求给定的源点$s$到达点$u(1\leq u \leq n)$的最短路长度。


思路

如果暴力建边的话,最坏情况会有$q\times n$条边。

对于区间操作,考虑线段树优化建边。

原$n$个点仍然保留,作为线段树的叶子结点。假如连边$(v\to [l,r],w)$,那么$v$向线段树中代表$[l,r]$的结点连权值为$w$的边,但只是这样连上去了回不到$n$个叶子结点上,所以每个点要向其左右儿子连权值为0的边。

因为这棵线段树中代表$[l,r]$的结点向叶子结点的路径长度已经为0,所以对于第三种操作$([l,r]\to v, w)$,需要建另外一棵线段树,代表$[l,r]$的结点向$v$连权值为$w$的边,每个点向父亲结点连权值为0的边。

线段树结点从$n+1$开始编号,叶子结点直接用$1\sim n$编号更方便,对于操作1可以直接连边。

用优先队列优化的Dijkstra算法求单源最短路,最终时间复杂度为$O(qlog^2n)$。


代码实现

#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
#define lson son[rt][0]
#define rson son[rt][1]
typedef long long LL;
typedef std::pair<LL, int> P;
const LL INF=0x3f3f3f3f3f3f3f3fll;
const int N = 100010 << 3, M = 5000010;
struct Edge
{
    int to, nex, w;
} edge[M];
int head[N], cnt_e, tot;
int son[N][2];
LL dis[N];
void init() {
    memset(head, 0, sizeof(head));
    cnt_e = 0;
}
void add_edge(int u, int v, int val) {
    edge[++cnt_e].to = v;
    edge[cnt_e].w = val;
    edge[cnt_e].nex = head[u];
    head[u] = cnt_e;
}
void build(int &rt, int L, int R, int tp) {
    if (L == R) { rt = L; return ; }
    rt = ++tot;
    int mid = (L + R) >> 1;
    build(lson, L, mid, tp);
    build(rson, mid + 1, R, tp);
    if (tp == 2) {
        add_edge(rt, lson, 0);
        add_edge(rt, rson, 0);
    }
    else {
        add_edge(lson, rt, 0);
        add_edge(rson, rt, 0);
    }
}
void modify(int l, int r, int L, int R, int rt, int u, int w, int tp) {
    if (L >= l && R <= r) {
        tp == 2 ? add_edge(u, rt, w) : add_edge(rt, u, w);
        return ;
    }
    int mid = (L + R) >> 1;
    if (l <= mid) modify(l, r, L, mid, lson, u, w, tp);
    if (r > mid) modify(l, r, mid + 1, R, rson, u, w, tp);
}
void dijkstra(int s) {
    std::priority_queue<P, std::vector<P>, std::greater<P> > que;
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    que.push(P(0, s));
    while (!que.empty()) {
        P p = que.top(); que.pop();
        int v = p.second;
        if (p.first > dis[v]) continue;
        for (int i = head[v], u; i; i = edge[i].nex) {
            u = edge[i].to;
            if (dis[v] + edge[i].w < dis[u]) {
                dis[u] = dis[v] + edge[i].w;
                que.push(P(dis[u], u));
            }
        }
    }
}

int main() {
    int n, q, s;
    while (~scanf("%d %d %d", &n, &q, &s)) {
        init();
        int rt2, rt3;
        tot = n;
        build(rt2, 1, n, 2);
        build(rt3, 1, n, 3);
        int tp, u, v, l, r, w;
        while (q--) {
            scanf("%d", &tp);
            if (tp == 1) {
                scanf("%d %d %d", &u, &v, &w);
                add_edge(u, v, w);
            }
            else {
                scanf("%d %d %d %d", &v, &l, &r, &w);
                modify(l, r, 1, n, (tp == 2 ? rt2 : rt3), v, w, tp);
            }
        }
        dijkstra(s);
        for (int i = 1; i <= n; i++) printf("%I64d%c", (dis[i] == INF ? -1ll : dis[i]), " \n"[i==n]);
    }
    return 0;
}
View Code

 

posted @ 2019-08-21 00:14  _kangkang  阅读(153)  评论(0编辑  收藏  举报