zoukankan      html  css  js  c++  java
  • 【CF786B】Legacy

    题目链接

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

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

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

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

    用了链表方便算空间,一颗线段树$2n$个点,总共有$5n$个点。结构边$4n$条,每次加$O(log n)$条边,总共算$4n+qlog 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
  • 相关阅读:
    Linux Bash
    grep 及正则表达式
    Linux 文件系统
    Linux 操作系统基础
    常见的磁盘I/O和网络I/O优化技巧
    NIO的工作方式
    网络I/O 工作机制
    spring Boot环境下dubbo+zookeeper的一个基础讲解与示例
    深入分析Java I/O 工作机制
    CDN工作机制和负载均衡
  • 原文地址:https://www.cnblogs.com/Hansue/p/12923588.html
Copyright © 2011-2022 走看看