2017湖南大學ACM程式設計新生杯大賽
阿新 • • 發佈:2019-02-04
題意:
有n個城市,m條道路,每條道路都有一個建造費用
只能建成建造費用<=k的道路
已知k,求能互相連通的城市最多有多少對
就是說求把<=k的路都建好了之後,每個集合的互相連通的點數之和
一個集合中互相連通的點數 = p*(p-1)/2 其中p為集合中點的個數 ,這樣的操作次數就是n*m,顯然不行
當兩個不相連的城市團A,B合併時,會產生sizeA * sizeB個互相連通的城市,sizeAB表示集合中城市的個數
即每加入一條邊就會增加sizeA * sizeB個互相連通的城市(當AB不在同一個集合中時
ans[i] 記錄加入排序後的第i條邊後互相連通的城市個數 ans[i] = ans[i-1] + sizeA * sizeB || ans[i-1]
然後存一下就行了
找的時候二分找到第一個大於k的,然後取它的下一個答案就行了
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> using namespace std; const int N = 1e6 + 10; int n,m,q,k; int fa[N],ans[N]; int cost[N]; struct node{ int u,v,cost; }e[N]; bool cmp(node a,node b){ return a.cost<b.cost; } int find(int x){ return fa[x]==x ? x : fa[x] = find(fa[x]); } int cnt[N],now = 1; void slove(){ sort(e+1,e+1+m,cmp); for(int i=0;i<=n;i++) {fa[i] = i; cnt[i] = 1;} for(int i=1;i<=m;i++){ cost[i] = e[i].cost; if(e[i].cost>=N) break; int faa = find(e[i].u); int fbb = find(e[i].v); ans[i] = ans[i-1]; if(faa == fbb) continue; fa[fbb] = faa; ans[i] += cnt[faa]*cnt[fbb]; cnt[faa] += cnt[fbb]; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].cost); } slove(); scanf("%d",&q); while(q--){ scanf("%d",&k); if(k>=e[m].cost) printf("%d\n",ans[m]); else{ int pos = upper_bound(cost+1,cost+1+m,k) - cost; printf("%d\n",ans[pos-1]); } } return 0; }