当前位置: 代码迷 >> 综合 >> HDU 5441 Travel (生成树+并查集)
  详细解决方案

HDU 5441 Travel (生成树+并查集)

热度:21   发布时间:2023-11-15 15:08:41.0

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5441

#include<bits/stdc++.h>
using namespace std;#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define read(x,y) scanf("%d%d",&x,&y)
#define ll long long#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
const int  maxn =2e5+5;
const int mod=1e9+7;
const ll INF =1e18+7;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:给定一张图和q个询问,
要求边不大于给定权限的符合要求,
那么不难想到会有联通快,直接用并查集统计下联通快即可,
但有个小问题,两个联通快合并的问题,稍微推一下就知道递增关系,
其他的都是老套路了,离线查询,把边排序,然后按边建立联通快。*/
int n,m,q;
struct edge
{int x,y,z;bool operator<(const edge& y) const{return z<y.z;}
}e[maxn];struct qy
{int a,b,id;bool operator<(const qy& y) const{return a<y.a;}
}query[5005];///并查集
ll pre[maxn],block[maxn];
int Find(int x){return pre[x]==x?x:pre[x]=Find(pre[x]);}ll ret[5050];
int main()
{int t;scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&m,&q);for(int i=0;i<m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);sort(e,e+m);for(int i=0;i<q;i++){scanf("%d",&query[i].a);query[i].id=i;}sort(query,query+q);ll ans=0;for(int i=0;i<maxn;i++) pre[i]=i,block[i]=1;for(int i=0,j=0;i<q;i++){while(j<m&&query[i].a>=e[j].z){int tx=Find(e[j].x),ty=Find(e[j].y);if(tx!=ty){ll bx=block[tx],by=block[ty];ans+=(bx+by)*(bx+by-1);ans-=(bx*(bx-1)+by*(by-1));block[ty]+=block[tx],pre[tx]=ty;}j++;}ret[query[i].id]=ans;}for(int i=0;i<q;i++) printf("%lld\n",ret[i]);}return 0;
}