• [PA2012]Tax


    Description

    给定一个图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权。求 (1)(n) 的最短路。

    Solution

    如果直接在这个图上跑的话,需要记录一下是从哪条边转移过来的,不太行。换一种思路,因为都是在和边打交道,不妨将边抽成点,建一个新图。点权就是原边权,边就是原图的点,边权就是新图两个点的较大值。但是这样的建图是 (m^2) 的。考虑到取 (max) 这个操作具有单调性。将原图一个点所连的边按边权排序后,一种权值对应的其实是一个前缀,所以考虑前缀优化。这样就可以直接跑了。注意建超级源汇点,以及拆边要拆成两条有向边。

    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    
    typedef long long ll;
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    const int N=1e5+7;
    const int M=4e5+7;
    
    int s,t,n,m;
    
    struct E_{
        int id; ll w;
        E_(int id_=0,ll w_=0):id(id_),w(w_){}
        bool operator <(const E_ &X)const{return w>X.w;}
    };
    
    int head[M],cnt=1;
    struct E{int next,to,w;}e[M<<5];
    
    inline void add(int id,int to,int w){
        e[++cnt]=(E){head[id],to,w};
        head[id]=cnt;
    //    printf("Link %d %d %d
    ",id,to,w);
    }
    
    ll dis[M];
    priority_queue<E_> Q;
    bool vis[M];
    vector<E_> g[N];
    
    int main(){
        n=read(),m=read();
        for(int i=1,u,v,w;i<=m;i++){
            u=read(),v=read(),w=read();
            g[u].push_back(E_(++cnt,w));
            g[v].push_back(E_(++cnt,w));
        }
        s=1,t=cnt+1; cnt=0;
        for(int i=1;i<=n;i++){
            sort(g[i].begin(),g[i].end());
            E_ lt; bool tag=0;
            for(E_ x:g[i]){
                if(tag){
                    add(lt.id,x.id,0);
                    add(x.id,lt.id,lt.w-x.w);
                }
                add(x.id,x.id^1,x.w);
                tag=1,lt=x;
            }
        }
        for(E_ x:g[1]) add(s,x.id,x.w);
        for(E_ x:g[n]) add(x.id^1,t,x.w);
        for(int i=s;i<=t;i++) dis[i]=1ll<<50;
        dis[s]=0,Q.push(E_(s,0));
        while(!Q.empty()){
            E_ t=Q.top(); Q.pop(); int u=t.id;
            if(vis[u]) continue; vis[u]=1;
            for(int i=head[u];i;i=e[i].next){
                int v=e[i].to;
                if(dis[v]>dis[u]+e[i].w){
                    dis[v]=dis[u]+e[i].w;
                    if(!vis[v]) Q.push((E_){v,dis[v]});
                }
            }
        }
        printf("%lld",dis[t]);
    }
    
  • 相关阅读:
    Ubuntu把在任事器范围起更次要的脚色
    linux下firefox 3.0 flash失效的治理法子
    Fedora的一些根蒂设置装备摆设(三、有关Firefox的放慢设置装备摆设)
    Linux操纵零碎下即时通讯软件
    QGtkStyle 让 KDE 法式拥有 Gnome 外不雅
    Ubuntu 8.04 告白登岸德国柏林的地铁零碎
    关于linux的一些重要日记文件
    linux下挂载U盘进程
    对Fedora9的一些心得领会(另附一些末尾设置装备安插)
    使用distinct在mysql中查询多条不重复记载值的处理责罚步调
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15209522.html
Copyright © 2020-2023  润新知