最小生成树专项

news/2024/10/8 18:50:06/文章来源:https://www.cnblogs.com/spdarkle/p/18452284

contests-link

A

求最短路啊

那显然只需要看端点颜色不同的边即可

那么依次考虑每条边的贡献

一个想法是暴力修改,不过菊花就死了

一个想法是把颜色相同且相连的点缩在一起然后求剩下边的min,现在至少剩下两个连通块

那根据Boruvka知道,这剩下的最优边必然是MST上的边(对于n个点任意划分为若干个集合,不同集合两两之间最小边的最小值一定在MST上

建出Kruskal重构树?一个点造成贡献当且仅当子树内颜色个数不少于2?

也不太好感觉,可以支持加不支持删

暴力的话就是边太多就死了

由于我们求了MST,不妨一个点维护其到父亲的边的可行性,那么可以类比点分树的计算方法,我们每个点维护到儿子的所有边的贡献,这样可以将点权影响的边变为只需要整体改动和单点修改

发现边应当按照颜色分类,所以我们利用 set map<int,multiset<int>> 存下每个点的每个儿子的边按照颜色分类后的边权最值。

这样的话,答案可以对于每个点单独算,而更改一个点的颜色,相当于是更改了那个点的2个set 对答案的贡献状态,可以 \(O(\log n)\) 做,而考虑对父亲的也是单点修改。

B

考虑支配关系

如果有 \(a<b<c\) 其两两 \(\gcd\) 相同,则显然用 \(a-b,a-c\) 即可,也即 \(b-c\) 是无用的

这就被支配了

枚举 \(\gcd\) 即可

\(O(n\log n)\) 条边

C

根据差分的知识,原数组全零相当于差分数组全零,那么可以对于每个点求出 \(l,r\),则可以修改 \(l,r+1\) 两个单点(联动修改)

则所有修改的单点连通即可,跑 Kruskal 就 OK 了

D

没啥好说的,线段树分治,每一层扔掉不可能的边和一定能的边即可,其余递归解决,复杂度双 \(\log\)

不可能的边指:假定子树内将来会用到的所有边边权全是 \(inf\),也不可能用到的边(也就是本节点涉及的边跑 Kruskal,扔掉无法更新的)。

一定能的边指:假设子树内将来会用到的边边权全是 \(-inf\),也会用到的边(也就是先加入所有的将来边,然后再跑Kruskal仍然能够产生贡献的边)

显然,这样处理之后剩下的边只有 \(O(len)\) 条,下传到左右儿子即可。

很经典。

void sol(int x,int l,int r){sort(ad[x].begin(),ad[x].end());if(l==r){ll lst=dsu::top,tmp=res;for(auto [u,v,w]:ad[x])res+=dsu::merge(u,v)*w;ans[l]=res;res=tmp;dsu::del(lst);return ;}ll lst=dsu::top,tmp=res,mid=l+r>>1;vector<bool>ud(ad[x].size());for(auto [u,v,w]:pas[x])dsu::merge(u,v);for(int i=0;i<ad[x].size();++i){auto [u,v,w]=ad[x][i];if(dsu::merge(u,v))ud[i]=1;}dsu::del(lst);for(int i=0;i<ad[x].size();++i){if(ud[i]){dsu::merge(ad[x][i].u,ad[x][i].v);res+=ad[x][i].w;continue;}if(dsu::merge(ad[x][i].u,ad[x][i].v)){ad[lc].push_back(ad[x][i]);ad[rc].push_back(ad[x][i]);}}dsu::del(lst);for(int i=0;i<ad[x].size();++i)if(ud[i])dsu::merge(ad[x][i].u,ad[x][i].v);ad[x].clear();ad[x].shrink_to_fit();pas[x].clear();pas[x].shrink_to_fit();sol(lc,l,mid);sol(rc,mid+1,r);res=tmp;dsu::del(lst);
}

E

显然对于值相同的两个点连在一起是最优的,所以可以去掉相同值的贡献,也就是每个值只保留一个元素。

然后由于求最大生成树,考虑Kruskal,从大到小枚举边权,能连的一定连。

则假设现在枚举的边权是 \(x\),还剩下 \(a_1\sim a_m\) 满足 \(a_i\& x=x\)

则必然有 \(\forall i,j,a_i\&a_j=x\),否则已经提前处理。

且由于这个条件,可以推出 \(m\le \log V\),因为鸽巢原理( \(x\) 的零位最多每个位放一个数到极限了)。

所以可以暴力找扫一遍所有数合并即可。

找数这个步骤,可以在做 Kruskal 的同时做高维后缀和。

当然你可以 Boravka,朴素的想法是计算高维后缀和找最优决策,事实上 Trie 处理按位与往往将“1”子树与“0”子树合并在一起作为新的零子树,按位或同理(像线段树合并一样)每个点最多合并 \(\log V\) 次。

那么相当于每个点有颜色,你Trie维护树内不同颜色个数即可。

    for(int i=(1<<d)-1;i>=0;--i){if(!a[i]){for(int j=0;j<d;++j)if(a[i|(1<<j)]){a[i]=a[i|(1<<j)];break;}}if(!a[i])continue;for(int j=0;j<d;++j)if(a[i|(1<<j)]&&find(a[i])!=find(a[i|(1<<j)])){ans+=i;f[find(a[i])]=find(a[i|(1<<j)]);}}

F

首先可以给边赋权之后转化为WQS二分板子

另一个巧妙的想法是拿出必须边,也就是假定用所有白边后仍然需要的黑边,用所有黑边后仍然需要的白边。

这样的必经边拿出来后我们就能够保证连通了,接下来贪心先处理白边,在次数充足时贪心能加就加,次数用完了就加黑边即可。

G

将一个值的 \(x,y\) 拿出来,相当于是做变换

\(C\) 时,每个值的 \(x\) 已经归位,也就是每个行号已经OK了

那么可以发现得到一个 \(B\) 之后是可以求出 \(C\) 的,因为变换已经固定了。

所以就必须要满足 \(B\) 里每一列的行号不同,且满足后一定可行,否则就没办法重排。

所以我们只需要做 \(A\to B\) 这一步就好了,满足只移动每一行,然后使得每一列元素行号不同。

有点匹配的味道了

我们只关心每个元素的行号,要通过移动每一行是的每一列的元素值互不相同。

如果建立行列二分图,相当于是每一个列到每一行的边都染为不同颜色

而这个操作移动操作相当于是交换了一个行的两条出边。

你考虑依次调整每个颜色

这里显然有对称性,所以你的开始位置不重要

不过这里也可以看作行号相同的两个点不在同一列上

如果说割开看,相当于是把行号相同的 \(m\) 个元素拿出来,考虑一次性归位一种颜色,然后把 \(m\) 列拿出来组成一个二分图匹配,做 \(n\) 轮就行了,而且这玩意是正则图?

这玩意有后效性应该假了。

那么考虑每次求一列的答案

你对行和颜色建立二分图,行i向其包含的颜色 \(j\) 连接 \(c_{i,j}\) 条边表示该行颜色出现次数。

匹配后就可以拿出一列的答案,如果匹配完美

而且匹配完了之后左部右部每个点的度数全部减少 \(1\),且初始度数全部是 \(n\),局面本质不会改变(霍尔定理始终满足(每个点度数相同,又显然有 \(|E(N(S))|\ge |E(S)|\),而 \(\forall S, |E(S)|=k·|S|\),其中 \(k\) 是常数,所以有 \(|N(S)|\ge |S|\),随便拿出一组匹配之后是没有后效性的)),那就完了。

事实上这是正则图。

建立 \(k\) 正则二分图,随意拿出一组完美匹配不会影响局面,只会变为 \(k-1\) 正则二分图

不知道这个说法对不对,反正感觉说出来挺舒服,这个东西好像叫正则二分图 \(k\) 染色

输出方案真恶心。。。

使用网络流可以做到 \(O(m·(n\sqrt {n^2}))=O(mn^2)\)

H

二分图匹配模板题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/810120.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试-前端基础速刷-Vue

1. Vue中computed和watch的区别 两者用途不同啊!computed用于计算产生新的数据,watch用于监听现有数据。 computed有缓存,methods没有缓存。 computed有点儿像工厂模式(产生新的东西),watch像发布订阅模式。(是我目前的知识盲区) 2. Vue组件通讯有几种方式,尽量全面❗…

宝塔平替:1Panel-新一代的 Linux 服务器运维管理面板(附优惠码/推荐码)

什么是1Panel 1Panel是一款开源,现代化的新一代的 Linux 服务器运维管理面板!1Panel可以帮你实现的功能: 高效管理:用户可以通过 Web 图形界面轻松管理 Linux 服务器,实现主机监控、文件管理、数据库管理、容器管理等功能; 快速建站:深度集成开源建站软件 WordPress 和 …

大模型应用开发初探 : 基于Coze创建Agent

Coze(扣子)是字节跳动公司开发的新一代AI应用开发平台,使用这个AI应用开发平台,无论你是否有编码基础,都可以快速搭建基于大语言模型的各类AI Bot,还可以将Bot发布到其他渠道。对于一个AI Agent而言,最重要的能力就是任务规划、调用工具、知识库 和 记忆能力,而这些能力…

了解final关键字在Java并发编程领域的作用吗?

在Java并发编程领域,final关键字扮演着一个至关重要的角色。虽然很多同学熟悉final用于修饰变量、方法和类的基本用法,但其在并发环境中的应用和原理却常常被忽视。final关键字不仅仅是一个简单的修饰符,它在多线程编程中确保对象状态的可见性和不变性,这对于构建线程安全的…

20222325 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1.实验内容缓冲区溢出基本知识:堆栈、函数调用。 shellcode技术以及其在各平台的运用与防御。 BOF攻击防御技术。2.实验目标 本次实践的对象是一个名为pwn1的linux可执行文件。 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。 该程序同时包含…

用AI构建小程序可行吗?

AI工具在软件开发中扮演着越来越重要的角色,它可以帮助开发者提高效率、增强软件功能、降低开发门槛。通过合理选择和应用AI工具,可以显著提升软件开发的质量和效率。随着移动互联网的快速发展,多端应用的需求日益增长。为了提高开发效率、降低成本并保证用户体验的一致性,…

PyQt5 使用 QLabel 实现图像 360度 不间断旋转

PyQt5 使用 QLabel 实现图像 360度 不间断旋转 当我们需要实现让一个图像 360度 旋转时,比如:音乐播放器中播放时,歌曲封面的旋转效果,你可以尝试使用下面的方法 代码结构 本文中全部代码全在test_QLabel_whirling.py这一个文件中编码,步骤中有变动的地方会注释标注,无改…

systemverilog笔记

变量类型变量名 状态数 是否带符号 比特数logic 4 无 1bit 2 无 1byte 2 有 8shortint 2 有 16int 2 有 32longint 2 有 64integer 4 有 32time 4 无 64$isunknown(表达式):在表达式任意位出现X或者Z时返回1。 数组 数组初始化 使用单引号加大括号数组遍历 $size(数组)会返回

DSP概述及应用——TMS320DM6437ZDU4、TMS320DM6437ZWT6、TMS320DM6437ZWT7数字媒体处理器

TMS320DM6437采用基于超标量架构的C64x+内核,具有高效的乘法累加单元和多格式指令集,能够在单个时钟周期内执行两条指令,大大提高了运算速度和效率。概述:TMS320DM6437是一款DSP芯片,具有强大的处理能力和丰富的功能模块。 TMS320DM6437采用基于超标量架构的C64x+内核,具…

csp-s模拟10

rank 31,垫底了,T1 0pts,T2 18pts,T3 0pts,T4 50pts 状态有点不好,策略有问题,T4是可以切的,但是不知道为什么弃了。T1不会线性基寄。T3 奇怪结论题,T2 结论题。 在猜结论上还是不行。 T1 欧几里得的噩梦 用到了线性基线性无关的性质,将两个数连边,把环去掉,并查集判…

Kubernetes的Pod调度:让你的应用像乘坐头等舱!

一、Kubernetes 中 Pod 调度的重要性 在 Kubernetes 的世界里,Pod 调度就像是一个繁忙的交通指挥官,负责把小车(也就是我们的 Pod)送到最合适的停车位(节点)。调度不仅关乎资源的合理利用,还关乎应用的“生死存亡”,下面让我们来看看为什么调度这么重要。资源优化: 想象…

二叉树的概念、表示法、性质和操作

本文记述了二叉树的基本概念、表示法、性质和操作。 ◆ 概念 二叉树(以下也简称树)是一种存放多个元素的数据结构。每个元素称为结点,每个结点有左、右两个链接,每个链接要么指向其他结点,要么是空链接。 某个结点是它的左、右链接指向的结点的父结点,被指向的结点是其父…