G. Path Queries(并查集)

传送门传送门传送门
\(说实话,不看题解,怎么也想不到生成树啊\)

\(不过其实就是个并查集。\)

\(对边从小到大排序,对q从小到大排序\)

\(然后对于每一次的q,把满足条件的边合并\)

\(于是当两个连通块合并时,我们加上num_{连通块1}*num_{连通块2}\)

\(num表示连通块的节点数\)

#include <bits/stdc++.h>
using namespace std;
#define p(a,b) make_pair(a,b)
const int maxn=2e5+10;
typedef long long ll;
ll n,m,pre[maxn],num[maxn],ans;
int find(int x){
	return x==pre[x]?pre[x]:pre[x]=find(pre[x]);
}
void join(int q,int w){
	int fq=find(q),fw=find(w);
	if(fq==fw)	return;
	ans+=num[fw]*num[fq];
	num[fw]+=num[fq],num[fq]=0;
	pre[fq]=fw;
}
struct p{
	int u,v,w;
	bool operator < ( const p&tmp )	const{
		return this->w<tmp.w;
	}
}a[maxn];
ll da[maxn];
typedef pair<int,int>sss;
sss k[maxn];
void init(){
	for(int i=1;i<=n;i++)	pre[i]=i,num[i]=1;
}
int main()
{
	cin>>n>>m;
	init();
	for(int i=1;i<=n-1;i++)	cin>>a[i].u>>a[i].v>>a[i].w;
	for(int i=1;i<=m;i++)
	{
		cin>>k[i].first;
		k[i].second=i;
	}
	sort(k+1,k+1+m);sort(a+1,a+n);
	ll last=1;
	for(int i=1;i<=m;i++)
	{
		for(int j=last;j<=n-1;j++)
		if(a[j].w<=k[i].first)
			join(a[j].u,a[j].v),last++;
		else	break;
		da[k[i].second]=ans;
	}
	for(int i=1;i<=m;i++)	cout<<da[i]<<" ";
}
posted @ 2020-05-24 18:01  倾叶子佮  阅读(170)  评论(0编辑  收藏  举报