CF 786B Legacy

题意

给一张图,有以下连边方式:区间向点连边,点向区间连边。求单源最短路径。

\(n, m\leq 10 ^5\)

题解

有一个比较经典的做法是线段树优化建图,时间复杂度约为 \(O(n\log^2n)\)。也可以使用高级数据结构优化。不过不是本文的重点。

还有一个方法是不用线段树显式建图,直接用线段树维护最短路。分别考虑一下两种操作:

  • \(u\) 向区间连边:直接在用 \(u\) 松弛的时候对该区间取 \(\min\) 即可。
  • 区间向点 \(u\) 连边:注意到一个区间只会被区间内 \(dis\) 最小的点松弛,在枚举到区间的点时,直接在线段树上更新点 \(u\),然后把该区间删去即可。直接把区间对应到线段树上的结点即可。

对于两个操作分别开线段树维护。

时间复杂度:每个区间只会使用 \(1\) 次,每次更新对应的结点 \(O(log n)\)。总时间复杂度就是 \(O(n\log n)\)

代码

#include <bits/stdc++.h>

using ll = long long;
using pli = std::pair<ll, int>;
using pii = std::pair<int, int>;
#define mkp(a, b) std::make_pair(a, b)

const ll inf = 1LL << 60;
const int N = 1e5 + 10;

namespace Fast_IO
{
    const int bufsize = 1 << 22;
    inline char Getchar()
    {
        static char buf[bufsize], *p1 = buf, *p2 = buf;
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufsize, stdin), p1 == p2) ? EOF : *p1++;
    }

    template<typename T = int> inline T read()
    {
        T x = 0, f = 0; char ch = Getchar();
        while (!isdigit(ch)) f |= ch == '-', ch = Getchar();
        while ( isdigit(ch)) x = x * 10 + ch - '0', ch = Getchar();
        return f ? -x : x;
    }

    char Buf[bufsize], *fout = Buf;
    inline void flush() 
    {
        fwrite(Buf, 1, fout - Buf, stdout), fflush(stdout);
    }

    inline void print(char *s) { while (*s) *fout++ = *s++; }
    inline void print(char c) { *fout++ = c; }

    template<typename T> inline void Write(T u) 
    {
        u > 9 ? Write(u / 10), *fout++ = u % 10 + '0' : *fout++ = u + '0';
    }

    template<typename T> inline void write(T u, char ch = ' ') 
    {
        if (u < 0) print('-'), u = -u; Write(u), print(ch);
    }
}
using namespace Fast_IO;

struct Node {int l, r, w;};
std::vector<Node> vec[N];
int w[N]; ll dis[N];

struct SegmentTree1
{
    static const int M = N << 2;
    int del[M]; ll tag[M]; pli Min[M];
    #define mid ((l + r) >> 1)

    inline void down(int k, ll dat, int d)
    {
        if (d) del[k] = 1, tag[k] = inf + 10, Min[k] = mkp(inf + 10, -1);
        if (del[k]) return;
        Min[k].first = std::min(Min[k].first, dat);
        tag[k] = std::min(tag[k], dat);
    }

    inline void upd(int k)
    {
        del[k] = del[k << 1] & del[k << 1 | 1];
        Min[k] = del[k] ? mkp(inf + 10, -1) : std::min(Min[k << 1], Min[k << 1 | 1]);
    }

    inline void down(int k)
    {
        if (del[k]) return;
        down(k << 1, tag[k], 0), down(k << 1 | 1, tag[k], 0), tag[k] = inf;
    }

    inline void build(int k, int l, int r)
    {
        tag[k] = inf;
        if (l == r) Min[k] = mkp(inf, l), del[k] = 0;
        if (l != r) build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r), upd(k);
    }

    inline void Mod(int k, int l, int r, int ql, int qr, ll dat, int d = 0)
    {
        if (ql >  r || l >  qr) return;
        if (ql <= l && r <= qr) return down(k, dat, d);
        down(k), Mod(k << 1, l, mid, ql, qr, dat, d), Mod(k << 1 | 1 , mid + 1, r, ql, qr, dat, d), upd(k);
    }

    inline int query() {return Min[1].second;}
}T1;
// 区间取min 单点删除 查询全局最小值

struct SegmentTree2
{
    static const int M = N << 2;
    std::vector<pii> vec[M]; int del[M], vis[M];
    #define mid ((l + r) >> 1)

    inline void Add(int k, int l, int r, int ql, int qr, pii dat)
    {
        if (ql >  r || l >  qr) return;
        if (ql <= l && r <= qr) return vec[k].push_back(dat), void();
        Add(k << 1, l, mid, ql, qr, dat), Add(k << 1 | 1, mid + 1, r, ql, qr, dat);
    }

    inline void upd(int k, int l, int r, int p, ll dat, int n)
    {
        for (int i = 0; i < vec[k].size(); ++i)
        {
            int u = vec[k][i].first, idx = vec[k][i].second;
            if (!vis[idx]) T1.Mod(1, 1, n, u, u, (ll)::w[idx] + dat, 0), vis[idx] = true;
        }
        vec[k].clear();
        if (l != r) p <= mid ? upd(k << 1, l, mid, p, dat, n) : upd(k << 1 | 1, mid + 1, r, p, dat, n);
    }
}T2;

int main()
{
    int n = read(), m = read(), s = read();
    for (int i = 1; i <= m; ++i)
    {
        int opt = read(), u = read();
        if (opt == 1) 
        {
            int v = read(), w = read();
            vec[u].push_back(Node{v, v, w});
        }
        if (opt == 2)
        {
            int l = read(), r = read(), w = read();
            vec[u].push_back(Node{l, r, w});
        }
        if (opt == 3)
        {
            int l = read(), r = read(), w = read(); ::w[i] = w;
            T2.Add(1, 1, n, l, r, mkp(u, i));
        }
    }
    memset(dis, 0x3f, sizeof(dis));
    T1.build(1, 1, n), T1.Mod(1, 1, n, s, s, 0), dis[s] = 0;
    while (true)
    {
        pli dat = T1.Min[1]; int u = T1.query(); 
        if (u == -1 || dat.first >= 1e18) break;
        T1.Mod(1, 1, n, u, u, inf + 10, 1);
        T2.upd(1, 1, n, u, dis[u] = dat.first, n);
        for (int i = 0; i < vec[u].size(); ++i)
        {
            int l = vec[u][i].l, r = vec[u][i].r;
            T1.Mod(1, 1, n, l, r, vec[u][i].w + dis[u]);
        }
    }
    for (int i = 1; i <= n; ++i) write(dis[i] >= 1e18 ? -1 : dis[i]);
    return flush(), 0;
}

posted @ 2020-11-03 09:00  bo1949  阅读(100)  评论(0)    收藏  举报