Loading

CF786B Legacy (线段树优化建边)

CF786B Legacy

线段树优化建边。

首先 \(O(n^2)\) 建边会 \(MLE\),于是考虑优化。对于区间建边,我们可以用线段树优化建边。本质是用线段树上延迟标记的性质,可以先把边建在更大的节点上。

具体的,考虑维护两棵线段树,第一颗父亲向儿子连 \(0\) 边,表示大区间到小区间无代价,维护入边信息;第二颗儿子向父亲连边,表示小区间可以到大区间无代价,维护出边信息;两棵线段树的对于叶子节点也应连边,本质是同一个点。

对于操作 \(1\)任意两个叶子节点连边即可。

对于操作 \(2\)任意一棵的叶子结点连向第一棵的 \(\log n\) 个区间。

对于操作 \(3\),第二颗的 \(\log n\) 个区间连向任意一棵的叶子结点。

#include <bits/stdc++.h>
#define int long long 
using namespace std;
int read(){
    int x = 0, f = 1;
    char c = getchar();
    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + (c - '0');
        c = getchar();
    }
    return x * f;
}
int n, q, S;
int sum, cnt;
int a[3000010], w[100010 << 2];
int h[3000010], dis[3000010], vis[3000010];
struct node{
    int to, nxt, w;
}e[3000100];
void add(int u, int v, int w){
    e[++cnt].to = v;
    e[cnt].nxt = h[u];
    e[cnt].w = w;
    h[u] = cnt;
}
void build(int u, int l, int r){
    sum = max(sum, u);
    if(l == r){
        a[l] = u;
        return;
    }
    int mid = (l + r) >> 1;
    add(u, u << 1, 0);
    add(u, u << 1 | 1, 0);
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void build2(int u, int l, int r){
    if(l == r){
        return;
    }
    int mid = (l + r) >> 1;
    add((u << 1) + sum, u + sum, 0);
    add((u << 1 | 1) + sum, u + sum, 0);
    build2(u << 1, l, mid), build2(u << 1 | 1, mid + 1, r);
}
bool inrange(int l, int r, int L, int R){
    return (L <= l) && (r <= R);
}
void update(int u, int l, int r, int L, int R, int w, int v){
    if(inrange(l, r, L, R)){
        add(a[v], u, w);
        return;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) update(u << 1, l, mid, L, R, w, v);
    if(R > mid) update(u << 1 | 1, mid + 1, r, L, R, w, v);
}
void update2(int u, int l, int r, int L, int R, int w, int v){
    if(inrange(l, r, L, R)){
        add(u + sum, a[v], w);
        return;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) update2(u << 1, l, mid, L, R, w, v);
    if(R > mid) update2(u << 1 | 1, mid + 1, r, L, R, w, v);
}
struct com{
    int v, w;
    friend bool operator < (com a, com b){
        return a.w > b.w;
    }
}tmp;
void dij(int s){
    priority_queue<com> q;
    for(int i = 1; i <= sum * 2; i++) dis[i] = 1ll << 62;
    dis[s] = 0;
    q.push({s, 0});
    while(!q.empty()){
        int u = q.top().v;
        q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = h[u]; i; i = e[i].nxt){
            int v = e[i].to;
            if(dis[v] > dis[u] + e[i].w){
                dis[v] = dis[u] + e[i].w;
                tmp.v = v, tmp.w = dis[v];
                q.push(tmp);
            }
        }
    }
}
signed main(){
    n = read(), q = read(), S = read();
    build(1, 1, n), build2(1, 1, n);
    for(int i = 1; i <= n; i++) add(a[i], a[i] + sum, 0), add(a[i] + sum, a[i], 0);
    for(int i = 1; i <= q; i++){
        int opt, v, l, r, w;
        opt = read();
        if(opt == 1){
            v = read(), l = read(), w = read();
            add(a[v], a[l], w);
        }
        else if(opt == 2){
            v = read(), l = read(), r = read(), w = read();
            update(1, 1, n, l, r, w, v);
        }
        else if(opt == 3){
            v = read(), l = read(), r = read(), w = read();
            update2(1, 1, n, l, r, w, v);
        }
    }
    dij(a[S] + sum);
    for(int i = 1; i <= n; i++){
        if(dis[a[i]] == 1ll << 62) cout << -1 << " ";
        else cout << dis[a[i]] << " ";
    }
    cout << endl;
    return 0;
}
posted @ 2024-03-27 22:01  Fire_Raku  阅读(17)  评论(0编辑  收藏  举报