• BZOJ4289: PA2012 Tax


    BZOJ4289: PA2012 Tax

    Description

    给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权
    N<=100000
    M<=200000

    Input

    Output

    Sample Input

    4 5
    1 2 5
    1 3 2
    2 3 1
    2 4 4
    3 4 8

    Sample Output

    12

    题解Here!

    这个题一眼看去感觉不可做啊。。。
    关键就是建图。。。
    这是一个比较有技巧的建图方式。
    首先考虑暴力点的建图:
    常规操作:把每条无向边拆成两条有向边。
    把每条边看成一个点,对于两条边$a->b,b->c$:
    在这两条边之间连有向边,边权为这两条边的权值的较大值。
    新建源点$S$,汇点$T$,$S$向所有从$1$连出去的边连边,所有指向$n$的边向$T$连边。
    求$S->T$的最短路即可。
    这个方式显然复杂度是$O(m^2)$的,铁定$TLE$。。。
    所以考虑骚操作优化。

    我们用类似网络流中补流思想的方法:考虑利用差值来建边。
    依然把每条边$x-y$拆成$x->y,y->x$。
    枚举每个中转点$x$。
    将$x$的出边按权值排序,$x$的每条入边向对应的出边连该边权值的边,$x$的每条出边向第一个比它大的出边连两边权差值的边,$x$的每条出边向第一个比它小的出边连权值为$0$的边。
    新建源汇$S,T$,$S$向每条$1$的出边连权值为该边边权的边。
    每条$n$的入边向$T$连该边权值的边。
    跑$S->T$的最短路即可。

     

    注:
    1. 此题卡$SPFA$!此题卡$SPFA$!!此题卡$SPFA$!!!重要的事情说三遍!!!所以还是乖乖写堆优化$dijkstra$吧。。。
    2. 记得与路径长度有关的数组、变量都要开$long long$!
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 400010
    #define MAX (1LL<<60)
    using namespace std;
    int n,m,c=1,d=2,s,t;
    int head[MAXN],h[MAXN],stack[MAXN];
    long long path[MAXN];
    bool vis[MAXN];
    struct Edge{
    	int next,to;
    	long long w;
    }edge[MAXN],a[MAXN<<2];
    struct node{
        int x;
    	long long dis;
        bool operator <(const node &p)const{
            return dis>p.dis;
        }
    };
    priority_queue<node> q;
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline bool cmp(const int &p,const int &q){
    	return edge[p].w<edge[q].w;
    }
    inline int relax(int u,int v,long long w){
    	if(path[v]>path[u]+w){
    		path[v]=path[u]+w;
    		return 1;
    	}
    	return 0;
    }
    inline void add_edge(int u,int v,long long w){
    	edge[d].to=v;edge[d].w=w;edge[d].next=h[u];h[u]=d++;
    	edge[d].to=u;edge[d].w=w;edge[d].next=h[v];h[v]=d++;
    }
    inline void add(int u,int v,long long w){
    	a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
    }
    void dijkstra(){
        node u,v;
        for(int i=s;i<=t;i++){path[i]=MAX;vis[i]=false;}
        u.x=s;u.dis=path[s]=0;
        q.push(u);
        while(!q.empty()){
            u=q.top();
            q.pop();
            if(!vis[u.x]){
                vis[u.x]=true;
                for(int i=head[u.x];i;i=a[i].next){
                    v.x=a[i].to;
                    if(!vis[v.x]){
                        path[v.x]=min(path[v.x],path[u.x]+a[i].w);
                        v.dis=u.dis+a[i].w;
                        q.push(v);
                    }
                }
            }
        }
    }
    void build(){
    	int top;
    	for(int i=1;i<=n;i++){
    		top=0;
    		for(int j=h[i];j;j=edge[j].next)stack[++top]=j;
    		sort(stack+1,stack+top+1,cmp);
    		for(int j=1;j<=top;j++){
    			int now=stack[j],after=stack[j+1];
    			if(edge[now].to==n)add(now,t,edge[now].w);
    			if(i==1)add(s,now,edge[now].w);
    			add(now^1,now,edge[now].w);
    			if(j<top){
    				add(now,after,edge[after].w-edge[now].w);
    				add(after,now,0);
    			}
    		}
    	}
    }
    void work(){
    	dijkstra();
    	printf("%lld
    ",path[t]);
    }
    void init(){
    	int u,v,w;
    	n=read();m=read();
    	s=1;t=((m+1)<<1);
    	for(int i=1;i<=m;i++){
    		u=read();v=read();w=read();
    		add_edge(u,v,w);
    	}
    	build();
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    容斥原理学习(Hdu 4135,Hdu 1796)
    ACdream 1112
    CodeChef--Cards, bags and coins
    ACdream 1108(莫队)
    Hdu 2586(LCA)
    CodeChef--EQUAKE
    Hackerrank--Mixing proteins(Math)
    Clash Credenz 2014 Wild Card Round题解
    Codeforces 463D
    CodeChef August Lunchtime 2014 题解
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9557241.html
Copyright © 2020-2023  润新知