zoukankan      html  css  js  c++  java
  • HDU 4750 Count The Pairs ★(图+并查集+树状数组)

    题意

    给定一个无向图(N<=10000, E<=500000),定义f[s,t]表示从s到t经过的每条路径中最长的边的最小值。Q个询问,每个询问一个t,问有多少对(s, t)使得f[s, t] >= t((s,t)和(t,s)是两对)

    思路

    按边权从小到大排序。考虑从小到大往图中加边同时计算以加入的边为f值的点对数。 难点和重点在于用并查集维护边的连通情况。 对于新加入的边(u, v),如果u,v原来便连通,则没有以该边为f值的点对,因为它一定不是最小边。 而如果(u, v)不连通,就可以把这条边能到达的点分为和u连通以及和v连通(分别和u、v在同一并查集中),那么分别从u、 v的连通集中取一个点组成的点对的f值都是这条边,即答案 = 2 * |Union(u)| * |Union(v)|。所以并查集还需要维护各自集中的点个数。 最后用树状数组维护一下前缀和,询问的时候二分+查询前缀和即可。

    代码

      [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; const int MAX = 500005; struct BIT{ int t[MAX<<1]; int bound; inline void init(int n){ bound = n; MEM(t, 0); } //lowbit(x):求2^q, q是x二进制最右边的1的位置. inline int lowbit(int x){ return x & (-x); } inline void update(int x, int v){ for (int i = x; i <= bound; i += lowbit(i)) t[i] += v; } inline int sum(int x){ int res = 0; for (int i = x; i >= 1; i -= lowbit(i)) res += t[i]; return res; } }bit; const int MAXN = 10005; struct Disjoint_Sets{ struct Sets{ int father, ranks, num; }S[MAXN]; inline void Init(int n){ for (int i = 0; i <= n; i ++){ S[i].father = i; S[i].ranks = 0; S[i].num = 1; } } inline int Father(int x){ if (S[x].father == x){ return x; } else{ S[x].father = Father(S[x].father); //Path compression return S[x].father; } } inline bool Union(int x, int y){ int fx = Father(x), fy = Father(y); if (fx == fy){ return false; } else{ //Rank merge int num1 = S[fx].num, num2 = S[fy].num; if (S[fx].ranks > S[fy].ranks){ S[fy].father = fx; } else{ S[fx].father = fy; if (S[fx].ranks == S[fy].ranks){ ++ S[fy].ranks; } } S[Father(fx)].num = num1+num2; return true; } } }DS; struct que{ int t, res; }q[100005]; struct edges{ int u, v, w; }e[500005]; bool cmp(edges n1, edges n2){ return n1.w < n2.w; } vector <int> adj[10005]; int main(){ int n, m; while(scanf("%d %d", &n, &m) != EOF){ for (int i = 0; i < m; i ++) scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w); sort(e, e+m, cmp); int Q; scanf("%d", &Q); for (int i = 0; i < Q; i ++){ scanf("%d", &q[i].t); q[i].res = 0; } for (int i = 0; i <= n; i ++) adj[i].clear(); DS.Init(n); bit.init(m); for (int i = 0; i < m; i ++){ if (DS.Father(e[i].u) != DS.Father(e[i].v)){ bit.update(m - i, 2*DS.S[DS.Father(e[i].u)].num*DS.S[DS.Father(e[i].v)].num); DS.Union(e[i].u, e[i].v); } } for (int i = 0; i < Q; i ++){ int t = q[i].t; int l = 0, r = m - 1; while(l < r){ int mid = MID(l, r); if (e[mid].w < t){ l = mid + 1; } else{ r = mid; } } while (l < m && e[l].w < t) l ++; printf("%d ", bit.sum(m - l)); } } return 0; } [/cpp]
  • 相关阅读:
    前后端渲染
    与你一起的日子
    Python 字符串转化成整形数组
    Python列出文件和目录
    Eclipse 导入Gson包
    java.lang.NoClassDefFoundError (Eclipse)
    成功的背后!(给所有IT人)
    事件与概率
    Servlet获取form表单上传文件及其他参数
    Servelt学习笔记之二——使用Servlet提取表单中的数据
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114345.html
Copyright © 2011-2022 走看看