CodeForces - 786B Legacy(线段树 +最短路+思维好题)

Legacy(传送门

题意

给定 n 颗行星,q次处理,地球位置为 s ,求解在q次处理后,地球到每一颗行星的位置。

其中 q 有三种不同的操作:

  1. 输入v,u,w,构建一条从 v u的代价为 w 的路线

  2. 输入u,l,r,w,构建一条从 u 到区间[l,r]中任意一颗行星的代价为 w 的路线

  3. 输入u,l,r,w,构建区间[l,r]中任意一颗行星到 u 的代价为w的路线

    解题思路

    由于涉及到区间操作,用线段树处理,主要是因为线段树处理在这道题简直是神思维。
    先通过构建一颗线段树,在线段树上构建边,边的构建方法如下:
    对于每一个线段树上的节点,构建一条节点到节点所管辖区域的每一个点价值为0的边,如下图 这里写图片描述

    然后构建一条从每一个点到包含它区间的代价为 0 的路线[此处建边有跟简单直观的,就是建立[l,l] l 的双向边,但是由于他们的代价为0再求最短路的时候会有点问题,导致有些点不会被访问,所以只能重新建立一遍新的节点用来充当区间的出路。],这样构建的边的个数基本就是 nlogn

    最后求一遍最短路就可以了

    代码

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <queue>
    
    
    #define lson rt << 1, l, mid
    #define rson rt << 1 | 1, mid + 1, r
    #define FIN freopen("input.txt", "r", stdin)
    using namespace std;
    typedef long long LL;
    typedef pair<LL, LL> PLL;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    const int MAXN = 3e5 + 5;
    int n,q, s, t, qn;
    vector<PLL> E[MAXN << 2];
    int ID[MAXN << 2], IDD[MAXN << 2];
    LL d[MAXN << 2];
    bool vis[MAXN << 2];
    
    void init(){
        for(int i= 0;i < MAXN;i ++){
            E[i].clear();
        }
    }
    
    void build(int rt, int l, int r, int flag){
        if(flag == 0) ID[rt] = ++ qn;//给每一个节点编号
        else IDD[rt] = ++ qn;
        for(int i = l;i <= r;i ++){
            if(flag == 0) E[ID[rt]].push_back(make_pair(i, 0));
            else E[i].push_back(make_pair(IDD[rt], 0));
        }
        if(l == r) return;
        int mid = (l + r) >> 1;
        build(lson, flag);
        build(rson, flag);
    }
    
    void update(int rt, int l, int r,int u, int L, int R, int w, int flag){
        if(L <= l && r <= R){
            if(flag == 0){
                E[u].push_back(make_pair(ID[rt], w));
            }
            else{
                E[IDD[rt]].push_back(make_pair(u, w));
            }
            return ;
        }
    
        int mid = (l + r) >> 1;
        if(L <= mid) update(lson, u, L, R, w, flag);
        if(R > mid) update(rson, u, L, R, w, flag);
    }
    
    priority_queue<PLL, vector<PLL>, greater<PLL> > Q;
    
    int main(){
        //  FIN;
        int u, v, w, l, r;
        while(~scanf("%d%d%d", &n, &q, &s)){
            init();
            qn = n;
            build(1, 1, n, 0);
            build(1, 1, n, 1);
            for(int i = 0;i < q;i ++){
                scanf("%d", &t);
                if(t == 1){
                    scanf("%d%d%d", &u, &v, &w);
                    E[u].push_back(make_pair(v, w));
                }
                else if(t == 2){//u -> [l, r]
                    scanf("%d%d%d%d", &u, &l, &r, &w);
                    update(1, 1, n, u, l, r, w, 0);
                }
                else if(t == 3){//[l, r] -> u;
                    scanf("%d%d%d%d", &u, &l, &r, &w);
                    update(1, 1, n, u, l, r, w, 1);
                }
            }
            memset(d, INF, sizeof(d));
            memset(vis, false, sizeof(vis));
            d[s] = 0;
            while(!Q.empty()) Q.pop();
            Q.push(make_pair(0, s));
            while(!Q.empty()){
                PLL e = Q.top();
                Q.pop();
                int u = e.second;
                if(vis[u]) continue;
                vis[u] = true;
                for(int i = 0;i < E[u].size();i ++){
                    PLL &ed = E[u][i];
                    if(!vis[ed.first] && d[ed.first] > d[u] + ed.second){
                        d[ed.first] = d[u] + ed.second;
                        Q.push(make_pair(d[ed.first], ed.first));
                    }
                }
            }
    
            for(int i = 1;i <= n;i ++){
                printf("%lld%c", d[i] == INF ? -1 : d[i], i == n ? '\n' : ' ');
            }
    
        }
        return 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值