【图论】CF1508C Complete the MST
有一张 \(n\) 个点的完全图,其中 \(m\) 条边已经标有边权。你需要给剩下的边都标上权值,使得所有边权的异或和为 \(0\),并且整张图的最小生成树边权和最小。
\(n,m\le 10^6, 1\le w_i<2^{30}\)。
注意到这道题是要让最小值最小,所以全程的决策都是由我们来决定的。
设已染色的边权和为 \(S\),那可以发现不会染两条以上的边,理由是 \(x+y\ge x\oplus y\)。只用考虑染一条 \(S\)。
记 \(ans'\) 为视每个补图连通块为一个点,最小生成树边权和。考虑什么情况下这条 \(S\) 边压根不会被算入答案。当所有未确定的边不构成森林的时候答案一定是 \(ans'\),因为随便弄出一棵最小生成树都一定有一条边不在里面,染成 \(S\) 即可。
否则最小生成树是森林,此时点数已经是 \(O(\sqrt m)\) 级别,可以直接枚举哪条边是 \(S\),时间复杂度 \(O(m\sqrt m)\)。如果这么做这道题就没意思了。
继续推性质。考虑我们有没有比 \(ans'+S\) 更优的方案。首先拿出我们当前的最小生成树,称其为 \(T\),则如果我们能省下一条补图的边不被选(用来放 \(S\)),那么在这棵补图树中割掉这条边后,一定会有恰好一边没在当前连通块中,所以需要新增恰好一条原图的边;反之,如果新增一条原图的边,且这条边的两端在 \(T\) 中不连通,则一定存在一条补图的树边可以被割掉。这两者形成一种双射。
所以从小到大枚举每条边看两个端点连不连通即可。
至于如何求出补图连通块,我们维护一个链表为当前还没有选的点,每次拿出链头,表示找到一个新的连通块,然后进行 bfs,每次对于一个点 \(u\),暴力遍历在链表中的所有点,如果不和 \(u\) 有连边则从链表中删除加入队列。由于每个点至多被删一次,并且每条边至多被访问一次而贡献时间复杂度,所以这部分是均摊线性的。
总时间复杂度 \(O(m\log m)\),瓶颈在于排序和用 set 判断边是否存在。
点击查看代码
#include <bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Rev(i,a,b) for(int i=a;i>=b;i--)
#define Fin(file) freopen(file,"r",stdin);
#define Fout(file) freopen(file,"w",stdout);
using namespace std;
const int N=2e5+5; using ll = long long;
struct Edge{int x,y,z;bool operator<(const Edge& ed)const{return z<ed.z;};}ed[N]; int ecnt;
int n,m,cp[N],ccnt,siz[N],ec[N],fa[N],flg[N]; set<int> S[N];
int getfa(int x) { return x==fa[x]?x:fa[x]=getfa(fa[x]); }
int main(){
cin>>n>>m; int s=0; For(i,1,m) { int x,y,z; cin>>x>>y>>z; s^=z; ed[++ecnt]={x,y,z}; S[x].insert(y),S[y].insert(x); }
sort(ed+1,ed+1+ecnt); list<int> lis; For(i,1,n) lis.push_back(i);
while(lis.size()){
ccnt++; queue<int> q; q.push(lis.front()); lis.pop_front();
while(q.size()){
int u=q.front(); q.pop(); cp[u]=ccnt;
for(auto it=lis.begin();it!=lis.end();){
if(!S[u].count(*it)) q.push(*it),lis.erase(it++); else it++;
}
}
}
For(u,1,n) { siz[cp[u]]++; for(int v:S[u]) if(cp[v]==cp[u]) ec[cp[u]]++; }
ll ans=0; int add=s; iota(fa+1,fa+1+ccnt,1);
For(i,1,ecnt){
int x=getfa(cp[ed[i].x]),y=getfa(cp[ed[i].y]); if(x!=y) flg[i]=1,ans+=ed[i].z,fa[y]=x;
}
For(i,1,ccnt) if(ec[i]/2+siz[i]-1!=1ll*siz[i]*(siz[i]-1)/2) cout<<ans<<'\n',exit(0);
iota(fa+1,fa+1+n,1); For(i,1,ecnt) if(flg[i]) fa[getfa(ed[i].y)]=getfa(ed[i].x);
For(i,1,ecnt) if(ed[i].z<add) {
int x=ed[i].x,y=ed[i].y; if(getfa(x)!=getfa(y)) { add=ed[i].z; break; }
}
cout<<ans+add<<'\n';
return 0;
}
【图论】CF1508C Complete the MST的更多相关文章
- 算法对比:Prim算法与Dijskra算法
在图论中,求MST的Prim算法和求最短路的Dijskra算法非常像.可是我一直都对这两个算法处于要懂不懂的状态,现在,就来总结一下这两个算法. 最小生成树(MST)—Prim算法: 算法步骤: •将 ...
- Codeforces Round #599 (Div. 1) B. 0-1 MST 图论
D. 0-1 MST Ujan has a lot of useless stuff in his drawers, a considerable part of which are his math ...
- 【图论 思维】cf715B. Complete The Graph加强
zzq讲的杂题 题目大意 有一张$n$个点$m$条边的简单正权无向图,$S$到$T$的最短路为$L$,现在有一些边的边权未知,请输出任意一种满足题意的方案. $n,m\le 500000$ ...
- NOI.AC 31 MST——整数划分相关的图论(生成树、哈希)
题目:http://noi.ac/problem/31 模拟 kruscal 的建最小生成树的过程,我们应该把树边一条一条加进去:在加下一条之前先把权值在这一条到下一条的之间的那些边都连上.连的时候要 ...
- D. Edges in MST 图论
http://codeforces.com/contest/160/problem/D base on 克鲁斯卡尔, 首先每次都是对权值相同的边进行统一处理,假如加入了当前这条边出现了回路,那就能确定 ...
- 图论 --- BFS + MST
Borg Maze Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7844 Accepted: 2623 Descrip ...
- poj 1679 The Unique MST 判断最小生成树是否唯一(图论)
借用的是Kruskal的并查集,算法中的一点添加和改动. 通过判定其中有多少条可选的边,然后跟最小生成树所需边做比较,可选的边多于所选边,那么肯定方案不唯一. 如果不知道这个最小生成树的算法,还是先去 ...
- [转] POJ图论入门
最短路问题此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等)http://acm.pku.edu.cn/JudgeOnline/problem?id=2449题意: ...
- HDU5627--Clarke and MST (bfs+位运算)
http://www.cnblogs.com/wenruo/p/5188495.html Clarke and MST Time Limit: 2000/1000 MS (Java/Others) M ...
- 一个完整的成年果蝇大脑的电子显微镜图谱 | A Complete Electron Microscopy Volume of the Brain of Adult Drosophila melanogaster
paper:A Complete Electron Microscopy Volume of the Brain of Adult Drosophila melanogaster 果蝇是一个非常完美的 ...
随机推荐
- 云图说|一张图看懂一站式DevOps利器——华为云DevCloud
阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要: 华为云DevCl ...
- 总结vue3 的一些知识点:MySQL 排序
MySQL 排序 我们知道从 MySQL 表中使用 SQL SELECT 语句来读取数据. 如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段 ...
- 火山引擎A/B测试:MAB智能调优实验,企业活动效果提升新利器
618临近,各大电商APP的预热活动已然拉开序幕.对企业而言,一场活动从策划到上线,中间经过效果验证,其业务成本很高.一个好的活动创意从策划.开发.到最终发布,至少会经历几周实践,如果中间还经历A ...
- 火山引擎 DataLeap:数据秒级生产,揭秘电商实时数仓最佳实践!
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 一年一度的「三八大促」刚刚落下帷幕,各大电商平台纷纷推出补贴.营销等玩法,力图推动持续增长.而电商平台持续增长,离 ...
- Axure 自定义元件库
点击文件 -> 新建元件库 可以添加多个元件,并将期重命名 保存元件库 新建页面 添加元件,选择自建的元件库 导入后就会发现我的原件库 这样就可以使用我们自定义的元件库了
- 【已解决】:Original error: Could not extract PIDs from ps output. PIDS: [], Procs: [“ps: uiautomator”]
报错截图 因为appium服务用的是1.4.x版本,使用的是 uiatumator1.0在android7.0得不到支持,所以获取PIDS得到空. 解决办法 找到Appium安装目录下node_mod ...
- 机器学习周刊 第4期:动手实战人工智能、计算机科学热门论文、免费的基于ChatGPT API的安卓端语音助手、每日数学、检索增强 (RAG) 生成技术综述
LLM开发者必读论文:检索增强(RAG)生成技术综述! 目录: 1.动手实战人工智能 Hands-on Al 2.huggingface的NLP.深度强化学习.语音课 3.Awesome Jupyte ...
- AtCoder Beginner Contest 163 (6/6)
比赛链接:Here AB水题, C - management 题意:给一棵 \(N(2\le N\le2e5)\) 个节点的有根树,求每个节点的儿子数. 思路:由于输入直接给的是每个节点的父节点,直 ...
- C# 序列化器
理论知识: 序列化是指将对象转换成字节流,从而存储对象或将对象传输到内存.数据库或文件的过程. 它的主要用途是保存对象的状态,以便能够在需要时重新创建对象. 反向过程称为"反序列化" ...
- Python追踪内存占用
技术背景 当我们需要对python代码所占用的内存进行管理时,首先就需要有一个工具可以对当前的内存占用情况进行一个追踪.虽然在Top界面或者一些异步的工具中也能够看到实时的内存变化,还有一些工具可以统 ...