简要题意

给你一个 \(N\) 个点,\(M\) 条边的 无向连通 带权图。给定一条边 \((u,v,L)\),请问需要在原图中删除多少条边,使得将 \((u,v,L)\) 插入图后,它既可能在最小生成树上,又可能在最大生成树上。

对于 \(100\%\) 的数据,满足 \(N\leq 20000,M\leq 200000,L\leq 20000\)。

思路

如果一条插入边 \((u,v,L)\) 后该边可能在最小生成树上,那么如果将边权小于 \(L\) 的边组成一个新图,则新图不连通。

证明:

  • 如果新图连通,则对新图求最小生成树,则最小生成树一定是原图的最小生成树(显然),然后 \((u,v,L)\) 就一定不在任意一个最小生成树中。与前句矛盾,所以必须不连通。
  • 如果新图不连通,则不存在最小生成树,使得任意一条树边边权小于 \(L\)。又因为原图连通,所以插入 \((u,v,L)\) 后,原图依旧连通。如果原图的最小生成树边集为 \(S\),则满足 \(\forall (x,y,z) \in S,z \geq L\)。 \((u,v,L)\) 插入 \(S\),则最小生成树变为基环树。将环上最大边权的边删除,则该边一定不是 \((u,v,L)\)(除非环上边权都相等),所以 \((u,v,L)\) 可能在插入后的最小生成树上。

(可能有一些不严谨,敬请指正)

同理可得:如果一条插入边 \((u,v,L)\) 后该边可能在最大生成树上,那么如果将边权大于 \(L\) 的边组成一个新图,则新图不连通。

所以如果我们建出了这两个新图,则相当于就是在求删除多少条边后全图(其实就是 \(u\to v\))不连通。最小割解决。

最后答案就是两图最小割答案和,由于两个图的割集的交集一定为空集(因为它们没有相同的点),所以可以加法原理。

最后说一句,为什么是题面可能是最小(最大)生成树呢,因为可能有边权相等的边。

时间复杂度 \(O(\operatorname{maxflow}(n,m))\),可以通过本题。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std; int n,m;
const int N = 200000+5,M = 200000+5;
int s,t,U,V,L,ret; namespace MaxFlow{
// 自己打一遍 Dinic 最大流,以防忘记
struct edge{
int nxt,to,w;
} g[M<<2];
int head[N],ec,dis[N],now[N];
bool vis[N];
void add(int u,int v,int w){
g[++ec].nxt=head[u];
g[ec].to=v;
g[ec].w=w;
head[u]=ec;
}
int bfs(){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
dis[s]=0;
now[s]=head[s];
vis[s]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i;i=g[i].nxt){
int v=g[i].to;
if(g[i].w>0 && !vis[v]){
q.push(v);
vis[v]=1;
now[v]=head[v];
dis[v]=dis[u]+1;
if(v==t){
return 1;
}
}
}
}
return 0;
}
int dfs(int x,int sum){
if(x==t){
return sum;
}
int k,res=sum;
for(int i=now[x];i&&sum;i=g[i].nxt){
now[x]=i;
int v=g[i].to;
if(g[i].w>0&&(dis[v]==dis[x]+1)){
k=dfs(v,min(res,g[i].w));
g[i].w-=k;
g[i^1].w+=k;
res-=k;
}
}
return sum-res;
}
int dinic(){
int ans=0;
while(bfs()){
ans+=dfs(s,LLONG_MAX);
}
return ans;
}
void addedge(int u,int v,int cap){
add(u,v,cap);
add(v,u,-cap);
} void clean(void){
ec=0;
memset(head,0,sizeof(head));
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(g,0,sizeof(g));
}
}
using namespace MaxFlow; struct Edge{int from,to,weight;};
vector<Edge> graph; signed main(){
cin>>n>>m;
for(int i=1,u,v,w;i<=m;i++){
cin>>u>>v>>w;
graph.push_back({u,v,w});
}
cin>>U>>V>>L;
s=U,t=V;
clean();
for(Edge i:graph){
if(i.weight < L){
addedge(i.from,i.to,1);addedge(i.to,i.from,1);
}
}
ret=dinic();
clean();
for(Edge i:graph){
if(i.weight > L){
addedge(i.from,i.to,1);addedge(i.to,i.from,1);
}
}
cout<<ret+dinic()<<'\n';
return 0;
}

最新文章

  1. PHPCMS与UCenter整合要点
  2. SqlServer性能检测和优化工具使用详细
  3. 关于Java内存模型的解读
  4. codeforces 349B Color the Fence 贪心,思维
  5. 【html5】常见标签使用说明(持续更新)
  6. ASP.NET\ASP.NET MVC表单提交遇到的问题结论
  7. Linux使用常见错误集锦
  8. Eclipse 和 Intellij idea 快捷键的区别
  9. 百度SEO优化
  10. 搭建自己的BT下载平台服务器
  11. 【问题解决】使用自定义控件时,vs停止工作
  12. asp.net core 2.0 查缺补漏
  13. IntelliJ IDEA 教程(1)
  14. java中的字符串分割函数
  15. JAVA面向对象-----抽象类
  16. springdataJAP的更新与保存的方法是同一个
  17. 基于scrapy-redis分布式爬虫的部署
  18. git官网和安装使用教程链接
  19. Python基础:一、编程语言分类
  20. 玩转 ”hello word“,Python程序员大多数都没有实现过

热门文章

  1. 后端框架的学习----mybatis框架(6、日志)
  2. python用ffmpeg进行视频处理
  3. SpringCloud微服务实战——搭建企业级开发框架(四十八):【移动开发】整合uni-app搭建移动端快速开发框架-使用第三方UI框架
  4. 【Bluetooth蓝牙开发】一、开篇词 | 打造全网最详细的Bluetooth开发教程
  5. HPL Study 1
  6. zk系列二:zookeeper实战之分布式统一配置获取
  7. 使用@Transactional注解的方法所在的类获取不到注解的解决方案
  8. JUC学习笔记——共享模型之管程
  9. 嵌入式学习-c语言篇01:搭建C语言环境
  10. 数组去重函数(unique)