(最小生成树(并查集加边法))2015网选,hdu5441 Travel

来源:互联网 发布:js 数字相加 编辑:程序博客网 时间:2024/06/01 08:38


/*题目:1005.Travel链接:http://acm.hdu.edu.cn/showproblem.php?pid=5441题目大意:给出n个顶点、m条边、k个x值,每条边有相应的权值;对每个x值,求只借助权值<=x的边而连通的顶点对有多少对?分析:最小生成树(并查集加边法)。    只需求一遍最小生成树,O(m)。    因为求解答案时,处理较大的x可以利用处理完较小的x留下的图(最小生成树的零碎部分),故将边按权值排序依次进行加边,将x从小到大排序依次处理。    对于当前x,加边加到权值>x的时候就不加了;处理下一个更大的x时,再继续在上一次停下的位置继续加。        答案利用求最小生成树的中间结果解。利用并查集记录以结点v为代表的结点集合的结点个数,则每加一条边{x,y},ans = ans - (root[x] * (root[x] - 1) + root[y] * (root[y] - 1)) + root[xy] * (root[xy] - 1); 优化:当已经得到一棵最小生成树时,便任意两点均连通,剩下的边都可以不处理。ps:只用并查集也可以,貌似用最小生成树的好处就只有那个优化。*/#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <queue>#include <vector>#include <set>#include <queue>#include <map>#include <algorithm>using namespace std;#define mem(x,i)   memset(x,i,sizeof(x))#define sfi(a)     scanf("%d", &a)  #define sfii(a,b)  scanf("%d %d", &a, &b)  #define sfiii(a,b,c)scanf("%d %d %d", &a, &b, &c)  const double EPS = 1e-10;const double pai = acos(-1.0);const int INF = 0xfffffff;const int MOD = 1000000007;typedef long long LL;const int maxq = 5000 + 5;struct Edge{    int u, v, w;    Edge(int u, int v, int w) :u(u), v(v), w(w){}    bool operator < (const Edge& e)const{        return w < e.w;    }};const int max_node = 20000 + 5;int root[max_node];struct UFS{    int S[max_node];    void init(int n){        for (int i = 1; i <= n; i++){            S[i] = i;            root[i] = 1;        }    }    int findset(int x){        return S[x] == x ? x : S[x] = findset(S[x]);    }    int merge(int x, int y){        return S[x] = y;    }}ufs;struct MST{    bool Kruskal(int &cnt, vector<Edge> &e,int &st, int x,int &ret){        if (cnt <= 1)return true;        for (int i = st; i < e.size(); i++){            if (e[i].w>x) return false;            st = i;             int x = ufs.findset(e[i].u);            int y = ufs.findset(e[i].v);            if (x != y){                ret -= (root[x] * (root[x] - 1) + root[y] * (root[y] - 1));                int xy = ufs.merge(x, y);                root[xy] = root[x] + root[y];                ret += root[xy] * (root[xy] - 1);                if (--cnt == 1)return true;            }        }        return false;    }}mst;struct NODE{    int no, x;    bool operator <(const NODE &b)const{        return x < b.x;    }    NODE(int x, int no) :x(x), no(no){}};vector<Edge> e;vector<NODE> x;int ans[maxq];int N, M, Q, X;int main(){    //freopen("f:\\input.txt", "r", stdin);    int T;    sfi(T);    while (T--){        sfiii(N, M, Q);        e.clear();        x.clear();        ufs.init(N);        for (int i = 0; i < M; i++){            int u, v, w;            sfiii(u, v, w);            e.push_back(Edge(u, v, w));        }        sort(e.begin(), e.end());        for (int i = 1; i <= Q; i++){            sfi(X);            x.push_back(NODE(X, i));        }        sort(x.begin(), x.end());         int st = 0, ret = 0, cnt = N;        for (int i = 0; i < x.size(); i++){            if (!mst.Kruskal(cnt, e, st, x[i].x, ret))                ans[x[i].no] = ret;            else                ans[x[i].no] = N*(N - 1);        }        for (int i = 1; i <= Q; i++){            printf("%d\n", ans[i]);        }    }    return 0;}


0 0