zoukankan      html  css  js  c++  java
  • Codeforces Round #582 (Div. 3)-G. Path Queries-并查集

    Codeforces Round #582 (Div. 3)-G. Path Queries-并查集


    【Problem Description】

    给你一棵树,求有多少条简单路径((u,v)),满足(u)(v)这条路径上的最大值不超过(k)(q)次查询。

    【Solution】

    并查集

    将所有边按权值从小到大排序,查询值(k_i)也从小到大排序。对于每次查询的值(k_i),将边权小于等于(k_i)的边通过并查集合并在一起。对于合并后的联通块,每个联通块对答案的贡献为(frac{size imes(size-1)}{2}),所有联通块的贡献直接求和即可。所以每次合并两个节点时,先将这两个节点所在的联通块的贡献减去,再加上合并后的贡献即可。


    【Code】

    /*
     * @Author: Simon 
     * @Date: 2019-09-07 10:00:30 
     * @Last Modified by: Simon
     * @Last Modified time: 2019-09-07 10:29:11
     */
    #include<bits/stdc++.h>
    using namespace std;
    typedef int Int;
    #define int long long
    #define INF 0x3f3f3f3f
    #define maxn 200005
    struct node{
        int u,v,w;
        node(){}
        node(int u,int v,int w):u(u),v(v),w(w){}
        bool operator <(const node&a)const{
            return w<a.w;
        }
    }g[maxn],q[maxn];
    int Set[maxn],Rank[maxn];
    void init(int n){ //初始化
        for(int i=0;i<=n;i++){
            Set[i]=i;Rank[i]=1;
        }
    }
    int cal(int x){ //计算联通块的贡献
        return x*(x-1)/2;
    }
    int Find(int u){ //并查集的查找根节点
        return Set[u]==u?u:Set[u]=Find(Set[u]);
    }
    int res=0;
    int ans[maxn];
    void merge(int u,int v){ //并查集的合并
        u=Find(u),v=Find(v);
        if(Rank[u]<Rank[v]) swap(u,v);
        res-=cal(Rank[u]),res-=cal(Rank[v]); //减去u,v所在联通块的贡献
        Set[v]=u;Rank[u]+=Rank[v]; //合并两个联通块
        res+=cal(Rank[u]); //再加上合并后的联通块的贡献
    }
    Int main(){
    #ifndef ONLINE_JUDGE
        //freopen("input.in","r",stdin);
        //freopen("output.out","w",stdout);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        
        int n,m;cin>>n>>m;init(n);
        for(int i=1;i<n;i++){
            cin>>g[i].u>>g[i].v>>g[i].w;
        }
        sort(g+1,g+n);
        for(int i=1;i<=m;i++){
            cin>>q[i].w;q[i].u=i;
        }
        sort(q+1,q+m+1);
        int pos=1;
        for(int i=1;i<=m;i++){
            while(pos<n&&g[pos].w<=q[i].w){
                merge(g[pos].u,g[pos].v);
                pos++;
            }
            ans[q[i].u]=res;
        }
        for(int i=1;i<=m;i++) cout<<ans[i]<<" 
    "[i==m];
    #ifndef ONLINE_JUDGE
        cout<<endl;system("pause");
    #endif
        return 0;
    }
    
  • 相关阅读:
    Linux启动或禁止SSH用户及IP的登录,只允许密钥验证登录模式
    emacs 入门教程,菜单汉化,配置文件等杂乱文章
    bzoj3376/poj1988[Usaco2004 Open]Cube Stacking 方块游戏 — 带权并查集
    NOIP复习篇
    HiHocoder 1036 : Trie图 AC自动机
    (皇后移动类)八数码难题引发的搜索思考及总结
    POJ 水题(刷题)进阶
    [TJOI2010] 中位数
    小球和盒子的问题
    [洛谷P2785] 物理1(phsic1)-磁通量
  • 原文地址:https://www.cnblogs.com/--Simon/p/11479662.html
Copyright © 2011-2022 走看看