Statement
[PA2012]Tax - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
Solution
dijkstra+最短路建模
题目的难点显然在于说怎么处理这个最大值的问题
嗯...先把一条双向边拆成两条有向边...权值在边不好搞,考虑边转点?...这个最大值有点像带悔贪心...
对于一个点,我们把与它有关的边分为入边和出边
(上图中 \(in,out\) 是对应的,因为原图是无向图)
先对边转成的点按照边权排序
考虑到最大值这个带悔贪心类似的东西,我们可以想到像这样连边
其中 \(\Delta w\) 表示的是两条边边权差。
这样连边之后,我们从 \(in_1\) 这边过来就有了选择的余地,比如想从 \(out_2\) 出去,会得到正确贡献
当我们从 \(in_2\) 过来的时候,因为取 \(max\) ,所以 \((out_2,out_1)\) 边权 \(0\) ,很妙
最后一个问题在于处理起点和终点,
非常好办,建立超级源点 \(s\) 和超级汇点 \(t\) , 然后所有从 \(1\) 出发的边,从 \(s\) 向这些边转成的点连原图权值的边
同样,所有结束于 \(n\) 的边,从这些边转的点向 \(t\) 连原图权值的边
跑一边 \(dijkstra\) 即可,这样连边,点数是 \(O(m)\) 的,边数是 \(O(m)\) 的,复杂度 \(O(m\log m)\)
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+5;
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}
struct Edge{
int nex,to;
int dis;
}edge[N<<3];
struct Line{
int v,w,id;
Line(int v,int w,int id):v(v),w(w),id(id){}
bool operator<(const Line&rhs)const{return w<rhs.w;}
};
struct node{
int v,w;
node(int v,int w):v(v),w(w){}
bool operator<(const node&rhs)const{return w>rhs.w;}
};
priority_queue<node>q;
vector<Line>Edge[N];
int head[N<<2];
int dis[N<<2];
int n,m,elen=1,s=0,t=1;
bool vis[N<<2];
bool chkmin(int &a,int b){return a>b?a=b,1:0;}
void addedge(int u,int v,int w){edge[++elen]={head[u],v,w},head[u]=elen;}
void dijkstra(){
memset(dis,0x3f,sizeof(dis));
q.push(node(s,dis[s]=0));
while(q.size()){
int u=q.top().v; q.pop();
if(vis[u])continue; vis[u]=1;
for(int e=head[u],v;v=edge[e].to,~e;e=edge[e].nex)
if(chkmin(dis[v],dis[u]+edge[e].dis))q.push(node(v,dis[v]));
}
}
signed main(){
memset(head,-1,sizeof(head));
n=read(),m=read();
for(int i=1,u,v,w;i<=m;++i)
u=read(),v=read(),w=read(),
Edge[u].push_back(Line(v,w,i<<1)),
Edge[v].push_back(Line(u,w,i<<1|1)),
addedge(i<<1,i<<1|1,w),addedge(i<<1|1,i<<1,w);
for(int i=1;i<=n;++i){
sort(Edge[i].begin(),Edge[i].end());
for(auto v:Edge[i]){
if(i==1)addedge(s,v.id,v.w);
if(v.v==n)addedge(v.id,t,v.w);
}
for(int j=1;j<(int)Edge[i].size();++j)
addedge(Edge[i][j].id,Edge[i][j-1].id,0),
addedge(Edge[i][j-1].id,Edge[i][j].id,Edge[i][j].w-Edge[i][j-1].w);
}
dijkstra();
printf("%lld\n",dis[t]);
return 0;
}