当前位置: 首页 > news >正文

CF757F 题解

题目传送门

思路

作为 CF2800 的紫题,这题的思维量还蛮大的,看洛谷上的题解全是支配树,鄙人技穷,不会,只能用其他方式来解决。

开局一个 Dijkstra,求出起点 sss 到各点之间的距离。

求完之后仍是一脸懵,但当你把各个点的最短路径记录下来时,你会发现,这形状很想一棵树。

没错,这就是我们熟悉的最短路树。

最短路树

所谓最短路树无非是将起点到各个点的最短路径保存下来(注意,可能有多条最短路径,这都要保留下来),所构成的图叫做最短路树(注意这是一个有向无环图(DAG))。

缩点

又有人要问了,要这图有什么用呢?

不难发现,在这个 DAG 中,如果我们删去的点是它到起点必须经过的点,那如果这个点被删,起点到它这只能换边,那么它的最短路径一定会发生改变。

有点绕自己理解一下。

这样我们可以考虑将删掉它后会发生更改的点记录一下,在最后枚举一下这个点所有会被它影响的点的数量,求最大值即可。

那么如何缩点呢?

我们可以考虑拓扑。

拓扑排序

想到这一点,作者本人也走了许多弯路,最开始用的普通循环来实现缩点,结果发现无法满足无后效性的问题(需要考虑后效性的原因是:这个点缩完后,无法保证后续是否在缩其它点时会不会重复计算,然后会挂在第 14 个点上)。

言归正传,书接上文

我们发现当出度唯一的点是会被起点到它的最短路径上的所有点限制的,但是如果出度 ≥2\ge 22 的点的多条路径没有都必须经过的点(起点除外),那么即使删去了一条最短路径上的点,它到起点的最短路径不会变。

同理,如果它到起点的路上必须经过某一个点,那这个点一删,它的最短路径必须改变。

原理已经讲完,但如何实现呢。

我们可以考虑并查集。

并查集

我们不难发现,如果能一步到达这个点的所有点(可以理解为这个点的父亲节点)都会在同一个点(不能是起点)删去后改变最短路长度,那么它也会被影响。

这启示我们可以拿个数组来统计当前这个点会在哪一个点删去后被影响。

到这里我们就不难想到用并查集来实现。

一些题外话

这道题卡了我一天,能思考到这真不容易,总共让作者交了 42 发:

不难发现作者始终因为后效性卡在了第 14 个点上,A 的那一刻是真的岔气了。

Code

#include <bits/stdc++.h>
#define inf 2e18
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef long long ll;
typedef long double ld; 
typedef int praise_long_long;
namespace io {using namespace std;inline ll read() {char n=getchar();ll num=0,flag=1;while(n<'0'||n>'9') {if(n=='-') {flag=-1;}n=getchar();}while(n>='0'&&n<='9') {num=num*10+n-'0';n=getchar();}return num*flag;}inline void print(ll x) {if(x<0) {putchar('-');print(-x);return;}if(x==0) {return;}print(x/10);putchar((char)(x%10+'0'));}
}
using namespace io;
const ll N=3e5+5;
struct node {ll vl,wl;
};
bool operator < (node a,node b) {return a.wl>b.wl;
}
vector<node> v[N],g[N],e[N];
priority_queue<node> q;
ll n,m,s,dis[N],du[N],f[N],cnt[N],mx;
bool vis[N];
queue<ll> que;
ll find(ll x) {if(x==f[x]) {return x;}return f[x]=find(f[x]);
}
void dij(ll s) {q.push({s,0});dis[s]=0;vis[s]=1;while(!q.empty()) {node d=q.top();q.pop();ll u=d.vl;vis[u]=0;for(auto it : v[u]) {ll wl=it.wl,vl=it.vl;if(dis[vl]>dis[u]+wl) {dis[vl]=dis[u]+wl;if(!vis[vl]) {q.push({vl,dis[vl]});vis[vl]=1;}}}}
}
void tosort() {for(ll i=1;i<=n;i++) {if(!du[i]) {que.push(i);}}while(!que.empty()) {ll d=que.front();que.pop();for(auto it : g[d]) {du[it.vl]--;if(!du[it.vl]) {que.push(it.vl);ll fa=-1;for(auto k : e[it.vl]) {if(fa==-1) {fa=find(k.vl);continue;}if(fa!=find(k.vl)) {fa=-1;break;}}if(fa==-1||d==s) {continue;}cnt[fa]+=cnt[find(it.vl)];cnt[find(it.vl)]=0;f[find(it.vl)]=fa;}}}
}
void solve() {memset(dis,0x3f,sizeof(dis));for(ll i=0;i<N;i++) {cnt[i]=1;}cin>>n>>m>>s;cnt[s]=0;for(ll i=1;i<=m;i++) {ll ul,vl,wl;cin>>ul>>vl>>wl;v[ul].push_back({vl,wl});v[vl].push_back({ul,wl});}dij(s);for(ll i=1;i<=n;i++) {for(auto it : v[i]) {if(dis[it.vl]==dis[i]+it.wl) {g[i].push_back(it);e[it.vl].push_back({i,it.wl});du[it.vl]++;}}f[i]=i;}tosort();for(ll i=1;i<=n;i++) {if(dis[i]==dis[0]||i==s) {continue;}// cout<<i<<' '<<cnt[i]<<endl;mx=max(mx,cnt[i]);}cout<<mx;
}
praise_long_long main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);ll T=1;
//	cin>>T;while(T--) {solve();}return 0;
}
/**/
http://www.dtcms.com/a/348189.html

相关文章:

  • SO_REUSEADDR
  • RuoYi-Vue3项目中Swagger接口测试404,端口问题解析排查
  • 【力扣】2623. 记忆函数——函数转换
  • 硬件抽象层 (HAL, Hardware Abstraction Layer)的简单使用示例
  • 邮箱创建时间打标与自动删除功能设计思路
  • UML时序图中opt,alt,switch-case的问题
  • 用户和组笔记
  • pion/webrtc v4.1.4 版本发布:关键特性与性能优化全面解析
  • 网络协议UDP、TCP
  • maven私服架构
  • Axure RP 9 交互原型设计(Mac 中文)
  • 【实习总结】快速上手Git:关键命令整理
  • 目标检测数据集 第007期-基于yolo标注格式的茶叶病害检测数据集(含免费分享)
  • 深度剖析Spring AI源码(一):蓝图初探,项目结构与设计哲学
  • 【嵌入式开发 Linux 常用命令系列 8 -- git checkout 解冲突详细介绍】
  • 【从零开始学习Redis】如何设计一个秒杀业务
  • [身份验证脚手架] 认证路由 | 认证后端控制器与请求
  • Zabbix 7.0中文乱码矫正
  • 网络协议---TCP
  • 论文阅读:VACE: All-in-One Video Creation and Editing
  • 机器学习算法-朴素贝叶斯
  • k8sday16调度器
  • Java全栈工程师面试实战:从基础到微服务的深度解析
  • 【运维进阶】高可用和负载均衡技术
  • 港口集装箱编号识别误识率↓79%!陌讯多模态融合算法落地优化
  • 静电服漏检率↓79%!陌讯多模态识别算法在智慧安检的实战解析
  • 下料口堵塞误报率↓79%!陌讯多模态融合算法在工业物料输送的实战解析
  • 电子厂静电释放检测误报率↓81%!陌讯多模态融合算法在安全生产监控的落地实践
  • 【Linux】Java线上问题,一分钟日志定位
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day12