hdu5441
题目描述:
在一张图中求出有多少对这样的点满足a关系?
a:相连并且路径上直接相连的两个点的边的权值小于给定的某个值,假设是x
因为询问不确定,所以可以先读取询问操作,按照我们想要的方式回答,然后按照原始顺序输出。
相连并且直接相连的每条边的权值小于x的点为一个集合,在这个集合中满足条件的点对有A(2,5),
假设给定的x大于这张图中所有边的权值,那么满足条件的点对有A(2,n)种;
但是x不确定,所以可以先给x从小到大排序,因为大x的答案肯定包含小x的答案,
然后图中边的权值从小到大排序,由x将边分块回答,采用并查集将一条边相连的点合并。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define maxn 105000 struct Edge { int from,to,dist; }edge[maxn]; int n,m,q; int answer[maxn]; struct node { int d,id; }que[5500]; bool cmp1(Edge a,Edge b) { return a.dist<b.dist; } bool cmp2(node a,node b) { return a.d<b.d; } int fa[maxn]; int Size[maxn]; void init() { for(int i=1;i<=n;i++) { fa[i]=i; //代表每个元素的父亲节点 Size[i]=1; //代表集合中有多少元素 } } int Find(int x) { if(x!=fa[x]) fa[x]=Find(fa[x]); return fa[x]; } void solve() { int ans=0; int j=1; for(int i=1;i<=q;i++) { for(;edge[j].dist<=que[i].d ;j++) { int from,to; from=edge[j].from; to=edge[j].to; if(from==to) continue; int t1,t2; t1=Find(from); t2=Find(to); if(t1==t2) //如果在一个集合,就不用合并 continue; ans+=2*Size[t1]*Size[t2]; fa[t2]=t1; Size[t1]+=Size[t2]; } answer[que[i].id]=ans; } for(int i=1;i<=q;i++) printf("%d\n",answer[i]); } int main() { //freopen("test.txt","r",stdin); int t; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&q); init(); for(int i=1;i<=m;i++) { scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].dist); } for(int i=1;i<=q;i++) { scanf("%d",&que[i].d); que[i].id=i; } sort(edge+1,edge+m+1,cmp1); sort(que+1,que+q+1,cmp2); solve(); } return 0; }