【BZOJ 4289】PA2012 Tax(技巧建圖最短路)
阿新 • • 發佈:2018-12-30
暴力做法:(30pts)
把每條無向邊拆成兩條有向邊.把每條邊看成一個點,對於兩條從一個點出去的邊 建兩條有向邊 邊權為較大值
這樣是m^2的
優化:
可以用類似差分的思想來 然後出邊之間做差分 對出邊的邊權排序 然後相鄰邊之間連邊(小邊向大邊連權值為兩邊權值之差的邊,大邊向小邊連權值為0的邊)
這樣入邊只需向他的對應邊連一個權值為原邊權的邊即可達到去最大值的效果。
#include<bits/stdc++.h> #define N 200005 #define ll long long #define INF 1000000000000000 using namespace std; template<class T> inline void read(T &x) { x=0; int f=1; static char ch=getchar(); while((!isdigit(ch))&&ch!='-') ch=getchar(); if(ch=='-') f=-1; while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); x*=f; } struct Edge { int to,next,val; }edge[2*N],road[8*N]; int n,m,tot=1,cnt=1,first[N],head[2*N],temp[N]; inline void addedge(int x,int y,int z) { tot++; edge[tot].to=y; edge[tot].next=first[x]; edge[tot].val=z; first[x]=tot; } inline void addroad(int x,int y,int z) { cnt++; road[cnt].to=y; road[cnt].next=head[x]; road[cnt].val=z; head[x]=cnt; } inline bool cmp(const int &a,const int &b) { return edge[a].val<edge[b].val; } int S,T; void Build() { S=1,T=2*(m+1); for(int i=1;i<=n;i++) { int top=0; for(int u=first[i];u;u=edge[u].next) temp[++top]=u; sort(temp+1,temp+top+1,cmp); for(int j=1;j<=top;j++) { int now=temp[j],next=temp[j+1]; if(edge[now].to==n) addroad(now,T,edge[now].val); if(i==1) addroad(S,now,edge[now].val); addroad(now^1,now,edge[now].val); //入邊和出邊 if(j<top) addroad(now,next,edge[next].val-edge[now].val),addroad(next,now,0); } } } ll dis[2*N]; typedef pair<ll,int> Pair; priority_queue<Pair,vector<Pair>,greater<Pair> > heap; bool vis[2*N]; void Dijkstra() { for(int i=2;i<=T;i++) dis[i]=INF; heap.push(make_pair(0,1)); while(!heap.empty()) { int now=heap.top().second; heap.pop(); if(vis[now]) continue; vis[now]=true; for(int u=head[now];u;u=road[u].next) { int v=road[u].to; if(dis[now]+road[u].val<dis[v]) { dis[v]=dis[now]+road[u].val; heap.push(make_pair(dis[v],v)); } } } } int main() { read(n),read(m); for(int i=1,x,y,z;i<=m;i++) read(x),read(y),read(z),addedge(x,y,z),addedge(y,x,z); Build(); Dijkstra(); cout<<dis[T]; return 0; }