abc 355 F - MST Query
题目链接:https://atcoder.jp/contests/abc355/tasks/abc355_f
题目要求动态维护最小生成树.
那么我们考虑朴素的Kruskal算法:将边从小到大排序,不断加边,用并查集维护联通块,加边加到整张图联通(联通块数量为1)为止,最后的答案就是从小到大遍历边权 将边的数量*当前边权 相加起来就是答案.
那么在这道题中,动态维护最小生成树的过程中我们唯一不知道的就是当前边权的边的数量.
然而在这道题中w的范围给的很小,最大只有10,所以在每次加边的时候我们都可以暴力遍历每种边权的边,然后直接对数量进行修改就行.
具体操作就是:初始化整张图有n个联通块,把给定的图分成10张图,用cnt[i]记录当边权为i时整张图有多少个联通块,每加一条边相当于减少一个联通块.那么在每次加边的时候我们去考虑当前权值以及比当前权值更大的那些权值(小的就不用考虑了,小的权值的连边情况不会变化).如果说在当前权值下当前加的这条边涉及到的两个点原本就是联通的,那么数量就不变;如果两点本来是不联通的,那么将这两点相连并更新联通块数量,开10个并查集去维护图的联通性.
最后cnt[i-1]-cnt[i]代表在权值为i的时候边的数量,用这个性质来计算最小生成树的权值即可.
代码:
struct DSU{
vector<int> fa,siz;
DSU(int n) :fa(n+1),siz(n+1,1){iota(fa.begin(),fa.end(),0);};
int find(int x)
{
while(x!=fa[x]) x=fa[x]=fa[fa[x]];
return x;
}
int size(int x) {return siz[x];}
bool same(int x,int y)
{
return find(x)==find(y);
}
bool merge(int x,int y)
{
x=find(x),y=find(y);
if(x==y)
{
return false;
}
siz[x]+=siz[y];
fa[y]=x;
return true;
}
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
vector dsu(10,DSU(n));
vector cnt(10,n);
for(int i=1;i<n;i++)
{
int u,v,w;
cin>>u>>v>>w;
for(int j=w;j<=10;j++)
{
cnt[j-1]-=dsu[j-1].merge(u,v);
}
}
while(m--)
{
int u,v,w;
cin>>u>>v>>w;
for(int j=w;j<=10;j++)
{
cnt[j-1]-=dsu[j-1].merge(u,v);
}
int ans=0;
int lst=n;
for(int j=1;j<=10;j++)
{
ans+=j*(lst-cnt[j-1]);
lst=cnt[j-1];
}
cout<<ans<<'\n';
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效