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]<<" ";
}