专栏文章
小可爱zzz绷不住逐步绷一眼秒的题 题解
P13948题解参与者 4已保存评论 4
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @minurwp8
- 此快照首次捕获于
- 2025/12/02 08:41 3 个月前
- 此快照最后确认于
- 2025/12/02 08:41 3 个月前
前言
小可爱zzz一眼秒了,但是我不会做。
做法来源,我的语文成绩不怎么样,所以感觉那篇题解的说明有些难以断句。我在这里再总结一下做法。
做法
由于原图是平面图,很难不想到先建出对偶图。
这里我们从图的每个顶点引出一条射线,将无限面划分成 小块,这样保证了对偶图是一棵树。
考虑题目所求,两点间的最大流即为 两点之间两段弧所对应的 两组代表无限面的点的 最短路。
找一些性质。
考虑对偶图上 所有连接无限面和有限面的边中 边权最小的边,记这条边是 。
这类边一定能找到 唯一 包含它的 边数最小的 一个环(这里指原图上的环),记其为 。
那么有结论:所有最短路要么与 没有交,要么与 有交 而且经过 。
可以感性理解一下。假设 引出的射线将图分成了上下两部分,而 在上部分,如图。

那么若最短路经过 且不经过 ,我们把 从 连向上半部分无限面的路径 替换成 即可。因为 是边权最小的连向无限面的边,所以一定不劣。
同时,由于边权非负,那么一个面一定不会被经过两次。这个结论就证完了。
考虑从原图上删除 ,并将 上其他边边权加上 的权值,形成一张新的图。
这里 在原图上删掉一条边 相当于 合并对偶图一条边连接的两个节点。
这里容易发现:
- 原图一条满足上述结论的路径 一定对应 新图上一条路径,且长度相等。这就说明了原图最短路大于等于新图最短路。
- 新图上一条路径的长度 一定大于等于 原图上对应路径的长度。这就说明了新图最短路大于等于原图最短路。
也就是说原图和新图上任一个点对,其最短路不变。那么我们直接删去这条边即可。这时 上的其他边就可能成为新的 ,继续删除最短的 ,直到图变为一棵树。此时点对间路径固定,使用 kruskal 重构树计算答案即可。
贴一下代码(应该可读):
CPPai3 ed[400040];
vpi t[400040];
int deg[400040];
bool flg[400040],rm[400040];
pii pt[400040];
int cn[400040];
int n,m,c;
void ade(int u,int v,int w){t[u].eb(v,w),t[v].eb(u,w),pt[w]=mkp(u,v);}
void solve(int _Tid) {
cin>>n>>m;
for(int i=1,u,v,w;i<=m;i++)cin>>u>>v>>w,u>v&&(swap(u,v),0),ed[i]={u,v,w};
// 建对偶图
sort(ed+1,ed+m+1,[&](const ai3&a,const ai3&b){return a[1]^b[1]?a[1]<b[1]:a[0]>b[0];});
vpi st;
for(int i=1;i<=m;i++){
++c;
while(st.size()&&ed[st.back().fi][0]>=ed[i][0])ade(st.back().se,c,st.back().fi),st.pop_back();
st.eb(i,c);
}
++c,ade(st.back().se,c,st.back().fi);
for(int i=1;i<=c;i++)deg[i]=t[i].size();
priority_queue<pii>pq;
for(int i=1;i<=m;i++)if(ed[i][0]==ed[i][1]-1||ed[i][0]==1&&ed[i][1]==n)pq.emplace(-ed[i][2],i),cn[i]=1,flg[deg[pt[i].fi]==1?pt[i].fi:pt[i].se]=1;else cn[i]=2;
// 不断删除一侧为无限面的边
while(pq.size()){
auto[w,id]=pq.top();
pq.pop();
if(!cn[id])continue;
int u=flg[pt[id].fi]?pt[id].se:pt[id].fi;
flg[u]=1,w=-w,rm[id]=1;
for(auto[v,id]:t[u])ed[id][2]+=w,(--cn[id])&&(pq.emplace(-ed[id][2],id),0);
}
vector<ai3>vec;
// 重构树计算答案
for(int i=1;i<=m;i++)if(!rm[i])vec.pb({ed[i][2],ed[i][0],ed[i][1]});
sort(all(vec),greater<>());
DSU d(n+1,-1);
ll res=0;
for(auto[w,u,v]:vec)if(d.getfa(u)!=d.getfa(v))res+=(ll)d[d.getfa(u)]*d[d.getfa(v)]%mod*w%mod,d.merge(u,v);
cout<<res%mod<<'\n';
}
相关推荐
评论
共 4 条评论,欢迎与作者交流。
正在加载评论...