最小生成树专项
A
求最短路啊
那显然只需要看端点颜色不同的边即可
那么依次考虑每条边的贡献
一个想法是暴力修改,不过菊花就死了
一个想法是把颜色相同且相连的点缩在一起然后求剩下边的min,现在至少剩下两个连通块
那根据Boruvka知道,这剩下的最优边必然是MST上的边(对于n个点任意划分为若干个集合,不同集合两两之间最小边的最小值一定在MST上)
建出Kruskal重构树?一个点造成贡献当且仅当子树内颜色个数不少于2?
也不太好感觉,可以支持加不支持删
暴力的话就是边太多就死了
由于我们求了MST,不妨一个点维护其到父亲的边的可行性,那么可以类比点分树的计算方法,我们每个点维护到儿子的所有边的贡献,这样可以将点权影响的边变为只需要整体改动和单点修改。
发现边应当按照颜色分类,所以我们利用 set map<int,multiset<int>>
存下每个点的每个儿子的边按照颜色分类后的边权最值。
这样的话,答案可以对于每个点单独算,而更改一个点的颜色,相当于是更改了那个点的2个set
对答案的贡献状态,可以
B
考虑支配关系
如果有
这就被支配了
枚举
有
C
根据差分的知识,原数组全零相当于差分数组全零,那么可以对于每个点求出
则所有修改的单点连通即可,跑 Kruskal 就 OK 了
D
没啥好说的,线段树分治,每一层扔掉不可能的边和一定能的边即可,其余递归解决,复杂度双
不可能的边指:假定子树内将来会用到的所有边边权全是
一定能的边指:假设子树内将来会用到的边边权全是
显然,这样处理之后剩下的边只有
很经典。
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,从大到小枚举边权,能连的一定连。
则假设现在枚举的边权是
则必然有
且由于这个条件,可以推出
所以可以暴力找扫一遍所有数合并即可。
找数这个步骤,可以在做 Kruskal 的同时做高维后缀和。
当然你可以 Boravka,朴素的想法是计算高维后缀和找最优决策,事实上 Trie
处理按位与往往将“1”子树与“0”子树合并在一起作为新的零子树,按位或同理(像线段树合并一样)每个点最多合并
那么相当于每个点有颜色,你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
将一个值的
在
那么可以发现得到一个
所以就必须要满足
所以我们只需要做
有点匹配的味道了
我们只关心每个元素的行号,要通过移动每一行是的每一列的元素值互不相同。
如果建立行列二分图,相当于是每一个列到每一行的边都染为不同颜色
而这个操作移动操作相当于是交换了一个行的两条出边。
你考虑依次调整每个颜色
这里显然有对称性,所以你的开始位置不重要
不过这里也可以看作行号相同的两个点不在同一列上
如果说割开看,相当于是把行号相同的
这玩意有后效性应该假了。
那么考虑每次求一列的答案
你对行和颜色建立二分图,行i向其包含的颜色
匹配后就可以拿出一列的答案,如果匹配完美
而且匹配完了之后左部右部每个点的度数全部减少
事实上这是正则图。
建立
不知道这个说法对不对,反正感觉说出来挺舒服,这个东西好像叫正则二分图
输出方案真恶心。。。
使用网络流可以做到
H
二分图匹配模板题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!