zoukankan      html  css  js  c++  java
  • 集合问题 离线+并查集 HDU 3938

    题目大意:给你n个点,m条边,q个询问,每条边有一个val,每次询问也询问一个val,定义:这样条件的两个点(u,v),使得u->v的的价值就是所有的通路中的的最长的边最短。问满足这样的点对有几个。

    思路:我们先将询问和边全部都按照val排序,然后我们知道,并查集是可以用来划分集合的,所以我们就用并查集来维护每一个集合就行了。

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    const int maxn = 1e5 + 5;
    const int maxm = 5e5 + 5;
    int n, m, Q;
    pair<int, pair<int, int> > p[maxm];///
    pair<int, int> q[maxn];///询问
    int par[maxn];
    LL sum[maxn], ans[maxn];
    
    int pfind(int x){
        if (x == par[x]) return x;
        return par[x] = pfind(par[x]);
    }
    
    int main(){
        while (scanf("%d%d%d", &n, &m, &Q) == 3){
            for (int i = 1; i <= m; i++){
                int u, v, val;
                scanf("%d%d%d", &u, &v, &val);
                p[i] = mk(val, mk(u, v));
            }
            sort(p + 1, p + 1 + m);
            memset(sum, 0, sizeof(sum));
            for (int i = 1; i <= n; i++) par[i] = i, sum[i] = 1;
            for (int i = 1; i <= Q; i++){
                int val; scanf("%d", &val);
                q[i] = mk(val, i);
            }
            sort(q + 1, q + 1 + Q);
            int j = 1; LL cnt = 0;
            for (int i = 1; i <= m && j <= Q; ){
                while (i <= m && p[i].first <= q[j].first){
                    int pa = pfind(p[i].second.first);
                    int pb = pfind(p[i].second.second);
                    i++;
                    if (pa == pb) continue;
                    cnt += sum[pa] * sum[pb];
                    ///printf("sum[%d] = %I64d sum[%d] = %I64d
    ", pa, sum[pa], pb, sum[pb]);
                    par[pa] = pb;
                    sum[pb] += sum[pa];
                }
                while (j <= Q && q[j].first < p[i].first){
                    ans[q[j].second] = cnt;
                    j++;
                }
            }
            while (j <= Q){
                ans[q[j].second] = cnt;
                j++;
            }
            for (int i = 1; i <= Q; i++){
                printf("%I64d
    ", ans[i]);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    如果你正在找工作,也许这七个方法会帮到你
    WebSocket 浅析
    关系数据库涉及中的范式与反范式
    MySQL字段类型与合理的选择字段类型
    ER图,数据建模与数据字典
    详解慢查询
    MySQL的最佳索引攻略
    后端技术演进
    MySQL主从复制(BinaryLog)
    MySQL读写分离
  • 原文地址:https://www.cnblogs.com/heimao5027/p/5873488.html
Copyright © 2011-2022 走看看