BZOJ4289 PA2012Tax(最短路)

  一个暴力的做法是把边看成点,之间的边权为两边的较大权值,最短路即可。但这样显然会被菊花图之类的卡掉。

  考虑优化建图。将边拆成两个有向边,同样化边为点。原图中同一条边在新图中的两个点之间连边权为原边权的边。对于原图同一点的出边按权值从小到大排序,权值相邻的由小到大连边权为差值的边,由大到小连边权为0的边。这样就完成了取max的操作。加上超源超汇即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 100010
#define M 200010
int n,m,p[M<<1],t=0;
long long d[M<<1];
bool flag[M<<1];
struct data{int to,nxt,len;
}edge[M<<3];
struct data3{int x,y,z,i;
}e[M<<1];
struct data2
{
    int x;long long d;
    bool operator <(const data2&a) const
    {
        return d>a.d;
    }
};
priority_queue<data2> q;
void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
void dijkstra()
{
    while (!q.empty()) q.pop();
    memset(d,42,sizeof(d));d[0]=0;q.push((data2){0,0});
    memset(flag,0,sizeof(flag));
    for (int i=1;i<=m*2+1;i++)
    {
        while (!q.empty()&&flag[q.top().x]) q.pop();
        if (q.empty()) break;
        data2 v=q.top();q.pop();
        flag[v.x]=1;
        for (int j=p[v.x];j;j=edge[j].nxt)
        if (v.d+edge[j].len<d[edge[j].to])
        {
            d[edge[j].to]=v.d+edge[j].len;
            q.push((data2){edge[j].to,d[edge[j].to]});
        }
    }
}
bool cmp1(const data3&a,const data3&b)
{
    return a.x<b.x;
}
bool cmp2(const data3&a,const data3&b)
{
    return a.z<b.z;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4289.in","r",stdin);
    freopen("bzoj4289.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();
    for (int i=1;i<=m;i++)
    e[i].x=e[i+m].y=read(),e[i].y=e[i+m].x=read(),e[i].z=e[i+m].z=read(),e[i].i=i,e[i+m].i=i+m,addedge(i,i+m,e[i].z),addedge(i+m,i,e[i].z);
    sort(e+1,e+m*2+1,cmp1);
    for (int i=1;i<=m*2;i++)
    {
        int t=i;
        while (t<m*2&&e[t+1].x==e[i].x) t++;
        sort(e+i,e+t+1,cmp2);
        for (int j=i;j<t;j++) addedge(e[j].i,e[j+1].i,e[j+1].z-e[j].z);
        for (int j=t;j>i;j--) addedge(e[j].i,e[j-1].i,0);
        i=t;
    }
    for (int i=1;i<=m*2;i++)
    {
        if (e[i].x==1) addedge(0,e[i].i,e[i].z);
        if (e[i].y==n) addedge(e[i].i,m*2+1,e[i].z);
    }
    dijkstra();
    cout<<d[m*2+1];
    return 0;
}

 

posted @ 2018-10-23 21:02  Gloid  阅读(166)  评论(0编辑  收藏  举报