zoukankan      html  css  js  c++  java
  • cf 786B

    建立两个线段树,第一个线段树是维护边的起点,即出边,第二个线段树维护边的终点,即入边
    同时对每个线段树上的点命名,叶子节点的命名用([1,n])即可,其他用线段树建立的顺序命名。
    比如对于第一棵线段树的建立
    在建立过程中,同时add边权为0的边,比如编号(n + 1)的点到(n+2)的点建立边,边权为0,表示(n+1)的区间能到达(n + 2)的区间,花费0

    同理,第二棵线段树也类似,只不过箭头是从下到上的


    操作一时,从入树叶子节点向出树叶子节点连边(红色的线)。

    操作二时,从入树叶子节点向出树所对应的区间节点连边(蓝色的线)。

    操作三时,从入树所对应的区间节点向出树叶子节点连边(绿色的线)

    对于一个点u,在区间([l,r])里,点v,在区间([x,y])里,且这四个两两存在边,那么对于从点u到v的方法有:

    • 直接从u到v走
    • 从u到([x,y]),再从([x,y])到v点
    • 从u到([l,r]),再从([l,r])到v点
    • 从u到([l,r]),再从([l,r])([x,y]),最后从([x,y])到v点
    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #define ll long long
    using namespace std;
    const int N = 1e5 + 5;
    const int M = 1e5 + 5;
    // const int INF = 0x3f3f3f3f;
    struct edge{
        int next, to;
        ll w;
    }e[M * 30];
    int head[N << 2], tot;
    inline void add(int u, int v, ll w){//链式前向星存图
        e[++tot].to = v;
        e[tot].w = w;
        e[tot].next = head[u];
        head[u] = tot;
    }
    struct node{
        ll dis;//dis表示到起始点的距离
        int pos;//pos表示该点的下标
        bool operator < (const node &x)const{//符号重载,对距离排序,针对于在优先队列里
            return x.dis < dis;
        }
    };
    ll dis[N << 2];
    bool vis[N << 2];
    void dijkstra(int s, int n){
        memset(dis, 0x3f, sizeof(dis)); dis[s] = 0;
        
        std::priority_queue<node> q;//构造优先队列
        q.push((node){dis[s], s});//把初始位置和距离放进优先队列
        while(!q.empty()){
            node tmp = q.top();
            q.pop();
            int u = tmp.pos;
            if(vis[u]) continue;//如果这个点走过了
            vis[u] = 1;//标记走过
            for(int i = head[u]; i; i = e[i].next){
                int v = e[i].to;
                if(!vis[v] && dis[v] > dis[u] + e[i].w){
                    dis[v] = dis[u] + e[i].w;
                    q.push((node){dis[v], v});
                }
            }
        }
    }
    
    int cnt1, cnt2, cnt, ls[N << 2], rs[N << 2];
    void build_out(int &p, int l, int r){ // 根编号是cnt1
        if(l == r) { // 对于叶子结点,编号为[1,n]
            p = l;
            return;
        }
        int mid = (l + r) >> 1; p = ++cnt; // 非叶子结点编号[n + i]
        build_out(ls[p], l, mid); build_out(rs[p], mid + 1, r);
        add(p, ls[p], 0); add(p, rs[p], 0); // 大区间到小区间建立边
    }
    void build_in(int &p, int l, int r){ // 根编号是cnt2
        if(l == r) {
            p = l;
            return;
        }
        int mid = (l + r) >> 1; p = ++cnt;
        build_in(ls[p], l, mid); build_in(rs[p], mid + 1, r);
        add(ls[p], p, 0); add(rs[p], p, 0);
    }
    void update1(int v, int p, int L, int R, int l, int r, int w){ // 点v到区间[l,r]
        if(l <= L && R <= r) {
            add(v, p, w);
            return;
        }
        int mid = (L + R) >> 1;
        if(l <= mid) update1(v, ls[p], L, mid, l, r, w);
        if(r > mid) update1(v, rs[p], mid + 1, R, l, r, w);
    }
    void update2(int v, int p, int L, int R, int l, int r, int w){ //区间[l,r]到点v 
        if(l <= L && R <= r) {
            add(p, v, w);
            return;
        }
        int mid = (L + R) >> 1;
        if(l <= mid) update2(v, ls[p], L, mid, l, r, w);
        if(r > mid) update2(v, rs[p], mid + 1, R, l, r, w);
    }
    int main(){
        int n, m, s;
        scanf("%d%d%d", &n, &m, &s);
        cnt = n;
        build_out(cnt1, 1, n); build_in(cnt2, 1, n);
        for(int i = 1; i <= m; i++) {
            int op, v, l, r, u, w;
            scanf("%d", &op);
            if(op == 1) {
                scanf("%d%d%d", &v, &u, &w);
                add(v, u, w);
            }
            if(op == 2) {
                scanf("%d%d%d%d", &v, &l, &r, &w);
                update1(v, cnt1, 1, n, l, r, w); // 在出边找区间
            }
            if(op == 3) {
                scanf("%d%d%d%d", &v, &l, &r, &w);
                update2(v, cnt2, 1, n, l, r, w); // 在入边找区间
            }
        }
        dijkstra(s, n);
        for(int i = 1; i <= n; i++)
            printf("%lld%c", dis[i] == dis[0] ? -1 : dis[i], " 
    "[i == n]);
        return 0;
    }
    
  • 相关阅读:
    618狂欢结束,来聊聊华为云GaussDB NoSQL的蓬勃张力
    用GaussDB合理管控数据资源的几点心得
    边缘计算告诉你们公司空调怎么开最省钱
    应对高并发,服务器如何笑而不“崩”
    父亲节程序员硬核示爱:你能看懂几条
    Spring Boot 之Spring data JPA简介
    将Spring Boot应用程序注册成为系统服务
    Spring Boot Admin的使用
    Spring Boot devtool的使用
    Spring Boot国际化支持
  • 原文地址:https://www.cnblogs.com/Emcikem/p/13417892.html
Copyright © 2011-2022 走看看