Gym102174G 神圣的 F2 连接着我们(线段树优化建图)

本题因为设计到区间到区间的连边,因此使用线段树优化建图

原理就是用out树和in树,一棵儿子向父亲连边,一棵父亲向儿子连边,然后叶子和叶子连边,对于两个区间的连边,用一个附加节点来表示连接。

建树使用动态开点,但是本题的内存需要计算,不然就会出现开大mle,小则re的尴尬情况

建完图后就是跑一下最短路即可。每个人的线段树优化建图都不相同,挑一个喜欢的模板即可,但是注意,有些模板题是只有点到区间或者区间到点,他们可能没有用附加节点。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=1e5+10;
const int M=1e5+10;
const ll inf=1e18;
int cnt;
int X[N],Y[N];
struct node{
    int l,r;
    int id;
}in[N<<2],out[N<<2];
struct pd{
    int id;
    ll w;
    bool operator <(const pd &t) const{
        return w>t.w;
    }
};
int n,m,p,Q;
int id1[18*N+2*M+2],id2[18*N+2*M+2];
vector<pd> g[18*N+2*M+2];
ll dis[18*N+2*M+2];
bool vis[18*N+2*M+2];
priority_queue<pd> q;
void add(int u,int v,int w){
    g[u].push_back({v,w});
}
int build(int k,int l,int r,node tr[],int *a,int type){
    tr[k]={l,r,++cnt};
    if(l==r){
        a[l]=cnt;
        return tr[k].id;
    }
    int mid=l+r>>1;
    if(type){
        add(tr[k].id,build(k<<1,l,mid,tr,a,type),0);
        add(tr[k].id,build(k<<1|1,mid+1,r,tr,a,type),0);
    }
    else{
        add(build(k<<1,l,mid,tr,a,type),tr[k].id,0);
        add(build(k<<1|1,mid+1,r,tr,a,type),tr[k].id,0);
    }
    return tr[k].id;
}
void modify(int u,int l,int r,int now,node tr[],int w,int type){
    if(tr[u].l>=l&&tr[u].r<=r){
        if(type)
            add(now,tr[u].id,w);
        else
            add(tr[u].id,now,w);
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)
        modify(u<<1,l,r,now,tr,w,type);
    if(r>mid)
        modify(u<<1|1,l,r,now,tr,w,type);
}
void dij(){
    while(q.size()){
        auto t=q.top();
        q.pop();
        if(vis[t.id])
            continue;
        vis[t.id]=1;
        for(int i=0;i<(int)g[t.id].size();i++){
            int j=g[t.id][i].id;
            if(dis[j]>dis[t.id]+g[t.id][i].w){
                dis[j]=dis[t.id]+g[t.id][i].w;
                q.push({j,dis[j]});
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>p>>Q;
    build(1,1,2*n,in,id1,0);
    build(1,1,2*n,out,id2,1);
    int i;
    for(i=1;i<=2*n;i++){
        add(id1[i],id2[i],0);
        add(id2[i],id1[i],0);
    }
    while(m--){
        int a,b,c,d,w;
        cin>>a>>b>>c>>d>>w;
        c+=n,d+=n;
        modify(1,a,b,++cnt,in,w,0);
        modify(1,c,d,cnt,out,0,1);
        modify(1,c,d,++cnt,in,w,0);
        modify(1,a,b,cnt,out,0,1);
    }
    for(i=1;i<=p;i++)
        cin>>X[i];
    for(i=1;i<=Q;i++){
        cin>>Y[i];
        Y[i]+=n;
    }
    for(i=1;i<=cnt;i++){
        dis[i]=1e18;
    }
    for(i=1;i<=Q;i++){
        dis[id1[Y[i]]]=0;
        q.push({id1[Y[i]],0});
    }
    dij();
    ll ans=0;
    for(i=1;i<=p;i++){
        ans=max(ans,dis[id2[X[i]]]);
    }
    if(ans==inf){
        cout<<"boring game"<<endl;
    }
    else{
        cout<<ans<<endl;
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13996121.html