1. 程式人生 > >2017湖南大學ACM程式設計新生杯大賽

2017湖南大學ACM程式設計新生杯大賽

題目連線

題意:

有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;
}