躲避拥挤
题目描述
小明很想出去走走。但是小明讨厌太拥挤的地方,她会拒绝一些人气旺盛的道路。有n个景点,有m双向道路。每条道路有一个人气值d ,表示这条道路的拥挤程度。小明不会经过那些人气值大于x的道路,他想知道有多少对景点 (a,b)使得从a景点出发可以到达b景点。
输入格式
第一行一个整数 T,表示有T 组数据。
对于每组数据,第一行有三个数n,m,q ,q 表示有 q 组询问。
接下来 m 行,每行三个数x,y,d ,表示有一条连接 x,y,人气值为 d 的道路。
最后 q 行,每行一个整数 x,代表询问。
输出格式
对于每组数据,输出q行,依次回答所有询问。
样例
样例输入
1
5 5 3
2 3 6334
1 5 15724
3 5 5705
4 3 12382
1 3 21726
6000
10000
13000
样例输出
2
6
12
样例解释:
拥挤程度不超6000的 道路有2--->3,有2对景点符合条件。分别是(2,3)(3,2)
拥挤程度不超10000的 道路有2--->3,3--->5,有6对景点符合条件。(2,3)(3,2)(3,5)(5,3)(2,5)(5,2)
拥挤程度不超13000的 道路有2--->3,3--->5,3--->4有12对景点符合条件。(2,3)(3,2)(3,5)(5,3)(2,5)(5,2)(4,3)(3,4)(2,4)(4,2)(4,5)(5,4)
分析:
求边长不大于x的各个连通块中元素个数c,景点对数为A(c,2)。累加所有连通块中的景点对数。
连接两个联通块A,B ,其中景点分别个数为cntA和cntB
则贡献的景点对数为 cntA*cntB*2
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define re register 4 #define LL long long 5 6 const int MAXN = 2e4+10; 7 int T,fa[MAXN]; 8 int cnt[MAXN];//cnt[i] 记录i所在的联通分量中的景点个数 9 LL ans[MAXN];//ans[i] 记录第i个询问的答案。 10 11 inline int find(int x){ 12 if(fa[x]==x) return x; 13 cnt[fa[x]]+=cnt[x];cnt[x]=0; 14 return fa[x]=find(fa[x]); 15 } 16 17 inline void write(long long x)//长整型数据输出 18 { 19 if(x < 0){putchar('-'); x = -x;} 20 if(x > 9)write(x / 10); putchar((x % 10) ^ 48); 21 return; 22 } 23 24 struct nod1{int x,y,d;}edges[MAXN*5]; 25 inline int cmp1(nod1 a,nod1 b) {return a.d<b.d;} //按拥挤程度从小到大排序 26 27 struct nod2{int id,x;}query[MAXN*5]; 28 inline int cmp2(nod2 a,nod2 b) {return a.x<b.x;} //按忍受极限从小到大排序 29 30 int main() { 31 32 cin>>T; 33 while(T--){ 34 35 int n,m,q;cin>>n>>m>>q; 36 for (re int i=1;i<=n;i++) cnt[i]=1,fa[i]=i; 37 38 for (re int i=1;i<=m;i++) cin>>edges[i].x>>edges[i].y>>edges[i].d; 39 sort(edges+1,edges+1+m,cmp1);//按拥挤程度从小到大排序 40 41 for (re int i=1;i<=q;i++) cin>>query[i].x,query[i].id=i; 42 sort(query+1,query+1+q,cmp2); //按忍受极限从小到大排序 43 44 LL res=0; 45 int edinx=1;//边序号,边已经按照拥挤程度从小到大排序了 46 for(re int i=1;i<=q;i++) //按忍受极限从小到大处理每个询问 47 { 48 //遍历每一条拥挤程度不大于忍受极限的边。 49 while((edinx<=m)&& (edges[edinx].d<=query[i].x)) 50 { 51 int l=find(edges[edinx].x); 52 int r=find(edges[edinx].y); 53 if(l!=r)//x,y不属于同一个联通分量,那要合并成一个联通分量。 54 { 55 fa[l]=r;//合并 56 57 //合并两个联通分量,增加了景点对数 58 res+=(LL)cnt[l]*cnt[r]*2; 59 //后一个询问的忍受极限一定大于等于前一个询问, 60 //所以后一个询问的结果继续累加,不能清零。 61 62 //合并后的大联通分量中的景点个数,为之前两个小联通分量之和。 63 cnt[r]+=cnt[l]; 64 cnt[l]=0; 65 } 66 edinx++; //处理下一条边 67 } 68 ans[query[i].id]=res; //按原来的询问顺序记录答案 69 } 70 71 // 按原来的询问次序输出答案 72 for(re int i=1;i<=q;i++) { 73 write(ans[i]); 74 //puts(""); 75 } 77 } 78 return 0; 79 }