Codeforces Round #582 (Div. 3)-G. Path Queries

地址:http://codeforces.com/contest/1213/problem/G

思路:並查集+離線查詢

對於m個查詢,先將其由小到大排序,這樣就能保證後面的答案一定包含前面的答案。

再將所有邊按照權值wi由小到大排序,對於第i小的查詢ti,將wi<ti的邊合併,其邊所貢獻的答案爲 邊兩邊所在集合的乘積 d[a]*d[b]

Code:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> pr;

const int MAX_N=2e5+5;
struct node{
	int u,v,w;
	bool operator<(const node &A){
		return w<A.w;
	}
};
int n,m;
int id[MAX_N];
LL d[MAX_N],ans;
node a[MAX_N];
pr que[MAX_N];
LL res[MAX_N];

int Find(int x){
	if(id[x]!=x)	id[x]=Find(id[x]);
	return id[x];
}
void Union(int a,int b){
	int fa=Find(a);
	int fb=Find(b);
	ans+=d[fa]*d[fb];
	id[fa]=fb;
	d[fb]+=d[fa];
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=0;i<=n;++i)
		id[i]=i,d[i]=1;
	int u,v,w;
	for(int i=1;i<n;++i)
	{
		cin>>u>>v>>w;
		a[i]={u,v,w};
	}
	sort(a+1,a+n);
	for(int i=0;i<m;++i)
	{
		cin>>w;
		que[i]={w,i};
	}
	sort(que,que+m);
	int t,li=1,l=0,r=0;
	int fa,fb;
	while(r<m){
		t=que[l].first;
		while(li<n&&a[li].w<=t){
			Union(a[li].u,a[li].v);
			++li;
		}
		while(l<m&&que[l].first==que[r].first){
			res[que[l].second]=ans;
			++l;
		}
		++r;
	}
	for(int i=0;i<m-1;++i)
		cout<<res[i]<<" ";
	cout<<res[m-1]<<endl;
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章