【CF786B】Legacy

题目链接

单点向区间连边,暴力转化为向区间内的每个点连边,显然会超时。

考虑建起两颗线段树,连向区间的边都连向“入树”,从区间连出的边都从“出树”连出,同时“入树”内按从根到叶子再到原单点的方向连边,“出树”内按从原单点到叶子再到根的方向连边,虚边(结构边)权值为零。

用样例二举例,画图如下:

我的做法是设置了节点结构体,图里区间上的标号就是数组下标。详见代码。

用了链表方便算空间,一颗线段树$2n$个点,总共有$5n$个点。结构边$4n$条,每次加$O(\log n)$条边,总共算$4n+q\log n$条边。

建好图之后跑堆优化Dijkstra就好了。

 

代码(100分):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define IL inline
#define RG register
#define _1 first
#define _2 second
using namespace std;
typedef long long LL;
const int N=1e5;
const int L=17;
const LL inf=1e14;

    int n,q,s;
    
struct Node{
    int l,r,ls,rs;
}t[N*5+3];
    int restop,tirt,tort;

struct Edge{
    int to,nxt;    LL cap;
}e[N*(6+L)+3];
    int top,h[N*5+3];
    
IL void add(int u,int v,LL w){
    top++;
    e[top].to=v;    e[top].nxt=h[u];    e[top].cap=w;
    h[u]=top;
}
    
void build(int i,int l,int r,int opt){            //opt1: tr_in;  opt2: tr_out
    t[i].l=l;    t[i].r=r;
    if(l==r){
        t[i].ls=t[i].rs=0;
        opt==1?add(i,l,0):add(l,i,0);
        return ;
        
    }
    
    int mid=(l+r)>>1;
    t[i].ls=++restop;    build(t[i].ls,l,mid,opt);
    t[i].rs=++restop;    build(t[i].rs,mid+1,r,opt);
    
    if(opt==1){    add(i,t[i].ls,0);    add(i,t[i].rs,0);}
    else 
    if(opt==2){    add(t[i].ls,i,0);    add(t[i].rs,i,0);}
    
}

void mdf(int i,int ql,int qr,int u,LL w,int opt){
    if(t[i].r<ql||qr<t[i].l)    return ;
    if(ql<=t[i].l&&t[i].r<=qr){
        opt==1?add(u,i,w):add(i,u,w);    return ;
    }
    
    int mid=(t[i].l+t[i].r)>>1;
    if(ql<=mid)
        mdf(t[i].ls,ql,qr,u,w,opt);
    if(qr>mid)
        mdf(t[i].rs,ql,qr,u,w,opt);
    
}

    LL dis[N*5+3];
    
struct Dat{
    LL v;    int d;
    Dat(){}
    Dat(LL p1,int p2):v(p1),d(p2){}
};

IL bool operator<(Dat x,Dat y){
    return x.v>y.v;
}

    priority_queue<Dat>hp;

IL void dij(int S){
    for(int i=1;i<=restop;i++)    dis[i]=inf;
    hp.push(Dat(dis[S]=0,S));
    
    while(!hp.empty()){
        Dat x=hp.top();    hp.pop();
        while(dis[x.d]<x.v&&!hp.empty()){
            x=hp.top();    hp.pop();
        }
        
        int u=x.d;
        for(int i=h[u];~i;i=e[i].nxt){
            int v=e[i].to;
            if(dis[u]+e[i].cap<dis[v])
                hp.push(Dat(dis[v]=dis[u]+e[i].cap,v));
            
        }
        
    }
    
}

int main(){
    scanf("%d%d%d",&n,&q,&s);
    memset(h,-1,sizeof h);
    top=-1;    restop=n;
    build(tirt=++restop,1,n,1);
    build(tort=++restop,1,n,2);
    while(q--){
        int opt,u,v,l,r;    LL w;
        scanf("%d%d",&opt,&u);
        
        if(opt==1){
            scanf("%d%lld",&v,&w);
            add(u,v,w);
            
        }
        else {
            scanf("%d%d%lld",&l,&r,&w);
            mdf(opt==2?tirt:tort,l,r,u,w,opt-1);
            
        }
        
    }
    
    dij(s);
    for(int i=1;i<=n;i++)
        printf("%lld ",dis[i]!=inf?dis[i]:-1);

    return 0;

}
View Code

 

posted @ 2020-05-20 14:51  汉谡  阅读(181)  评论(0编辑  收藏  举报