[ABC355F] MST Query 題解

yaaaaaan發表於2024-11-29

原題連結

link

題目大意

給你一棵 \(n\) 個點的帶邊權的樹,有 \(q\) 次詢問,每次詢問加一條帶邊權的邊,輸出當前的最小生成樹的邊權和。

思路

這道題我們觀察題目範圍,可知權值的範圍很小。所以我們考慮列舉權值,計錄這種權值的邊對答案的變化 \(dp_i\)

對於一條邊,我們用並查集記錄這條邊加進去會不會構成環。

  • 如果這條邊不會構成環不在最小生成樹內,則加入這條邊,變化量加上這條邊的權值。

  • 如果這條邊構成環在最小生成樹內,則去掉這條邊,變化量減去這條邊的權值。

最後對 \(dp\) 陣列求一遍字首和就是答案。

程式碼

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
int n,q;
int a[500005],b[500005],c[500005],dp[500005];
int num[500005];
int fa[500005];
int find(int x)
{
	if(fa[x]==x) return x;
	fa[x]=find(fa[x]);
	return fa[x];
}
bool merge(int x,int y)
{
	int xx=find(x),yy=find(y);
	if(xx==yy) return false;
	if(num[xx]>num[yy]) swap(xx,yy);
	num[yy]+=num[xx];
	fa[xx]=yy;
	return true;
}
bool fl[500005];
signed main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>q;
	for(int i=1;i<=n+q-1;i++)
	{
		cin>>a[i]>>b[i]>>c[i];
	}
	for(int i=1;i<=10;i++)
	{
		for(int j=1;j<=200005;j++) 
		{
			fa[j]=j;
			num[j]=1;
		}
		for(int j=1;j<=n+q-1;j++)
		{
			if(c[j]<=i)
			{
				if(merge(a[j],b[j]))
				{
					if(!fl[j])
					{
						fl[j]=1;
						dp[j]+=i;
					}
				}
				else
				{
					if(fl[j])
					{
						dp[j]-=i;
						fl[j]=0;
					}
				}
			}
		}
	}
	for(int i=1;i<=n+q-1;i++) dp[i]+=dp[i-1];
	for(int i=n;i<=n+q-1;i++)
	{
		cout<<dp[i]<<"\n";
	}
	return 0;
}



相關文章