CF786-lagacy 题解

CF786B-Lagacy

线段树优化最短路建边模版。

要同时建立两棵线段树,由于是动态开点线段树,可以只开一个tr结构体数组。一个线段树由区间(顶部)向下建边,另一个反过来建边,这样可以保证初始的时候节点之间两两不能互相到达。

动态开点要从n+1开始开点,最底部的节点仍然对应原来节点的编号,这样便于加边(当然不这么处理也可以写)。两棵线段树的最底部的节点是一致的。

加边的时候这棵树并不需要自顶向下做什么操作,实际上只是套了一个线段树的壳子来减少边的数量而已,实际上是在两棵线段树构成的图上跑最短路。对于操作一,直接加边即可。对于后两种,由于我们并不能O(1)给出一个区间对应的一个或多个节点,所以需要利用线段树查询的方式找到区间对应的节点,然后建立单向边。

#include <bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
#define ll long long
#define mid ((lo+ro)>>1)
const int maxn=4e5+10;
const ll inf=1e16;
struct xnode{
    int lo;int ro;
}tr[maxn*10];
int tot,n,q,s,rtin,rtou;
struct node{
    int v;ll w;
};
vector<node> all[maxn*10];
struct qnode{
    int pos;ll dis;
};
struct cmp{
    bool operator()(const qnode &a1,const qnode &a2){return a1.dis>a2.dis;}
};
priority_queue<qnode,vector<qnode>,cmp> k1;
ll dis[maxn*10];
bool vis[maxn*10];
void add1(int u,int v,ll w){
    all[u].push_back((node){v,w});
}
void buildin(int &now,int lo,int ro){
    now=++tot;
    if(lo==ro){now=lo;return;}
    int mid1=(lo+ro)/2;
    buildin(tr[now].lo,lo,mid1);
    buildin(tr[now].ro,mid+1,ro);
    add1(now,tr[now].lo,0);
    add1(now,tr[now].ro,0);
}
void buildou(int &now,int lo,int ro){
    now=++tot;
    if(lo==ro){now=ro;return;}
    int mid1=(lo+ro)/2;
    buildou(tr[now].lo,lo,mid1);
    buildou(tr[now].ro,mid1+1,ro);
    add1(tr[now].lo,now,0);
    add1(tr[now].ro,now,0);
}
void upd(int &now,int lo,int ro,int lr,int rr,int zhi,int tp,int pos){
    if(lr>=lo&&rr<=ro){
        if(tp==2) add1(pos,now,zhi);
        else add1(now,pos,zhi);
        return;
    }   
    int mid1=(lr+rr)/2;
    if(mid1>=lo) upd(tr[now].lo,lo,ro,lr,mid1,zhi,tp,pos);
    if(mid1<ro) upd(tr[now].ro,lo,ro,mid1+1,rr,zhi,tp,pos);
}
int main(){
    ios;fre();
    cin>>n>>q>>s;
    tot=n;
    buildin(rtin,1,n);
    buildou(rtou,1,n);
    for(int i=1;i<=q;i++){
        int tmp;cin>>tmp;
        if(tmp==1){
            int u,v,w;cin>>u>>v>>w;
            add1(u,v,w);
        }
        else{
            int r,lo,ro,w;cin>>r>>lo>>ro>>w;
            upd(tmp==2?rtin:rtou,lo,ro,1,n,w,tmp,r);
        }
    }
    for(int i=1;i<=tot;i++) dis[i]=inf;
    dis[s]=0;
    k1.push((qnode){s,0});
    while(!k1.empty()){
        int tmp=k1.top().pos;k1.pop();
        if(vis[tmp]) continue;
        vis[tmp]=1;
        for(int i=0;i<all[tmp].size();i++){
            int v=all[tmp][i].v,w1=all[tmp][i].w;
            if(vis[v]) continue;
            if(dis[v]>dis[tmp]+w1){
                dis[v]=dis[tmp]+w1;
                k1.push((qnode){v,dis[v]});
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(dis[i]==inf) cout<<-1<<' ';
        else cout<<dis[i]<<' ';
    }
    return 0;
}
上一篇:Oracle 数据字典表的使用


下一篇:快速排序算法实现及优化