• HDU 5441 Travel (离线dsu)


    <题目链接>

    题目大意:
    $n$个点,$m$条边,每条边具有对应的权值,然后进行$k$次询问,每次询问给定一个值,所有权值小于等于这个的边所对应的点能够相连,问每次询问,这些能够相互到达的点所构成的无序点对的个数。

    解题分析:
    数据比较大,每次询问暴力加边肯定超时,所以考虑离线来搞。进行离线查询,将查询按权值从小到大排序,然后每次询问就不需要全部重新添边,只需要增加多余的那一部分即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5+5 , M = 5e3+5;
    #define REP(i,s,t) for(int i=s;i<=t;i++)
    struct Edge{
        int u,v,val;
        bool operator < (const Edge&tmp)const{ return val<tmp.val; }
    }e[N];
    
    struct Que{ int id,val; }q[M];
    bool cmp(Que a,Que b){ return a.val<b.val; }
    
    typedef long long ll;
    int n,m,k;
    int rk[N],fa[N];
    ll ans,res[N];
    
    int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }
    
    inline void Union(int u,int v){
        int f1=find(u),f2=find(v);
        if(f1!=f2){
            ans+=rk[f1]*rk[f2]*2;      //贡献是两个集合点数的乘积
            rk[f1]+=rk[f2];      
            fa[f2]=f1;
        }
    }
    int main(){
        int T;cin>>T;
        while(T--){
            scanf("%d%d%d",&n,&m,&k);
            REP(i,0,n)fa[i]=i,rk[i]=1;
            REP(i,1,m)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].val);
            sort(e+1,e+1+m);
            REP(i,1,k)scanf("%d",&q[i].val),q[i].id=i;
            sort(q+1,q+1+k,cmp);
            ans=0;
            int loc=1;
            REP(i,1,k){
                while(loc<=m && e[loc].val<=q[i].val){
                    Union(e[loc].u,e[loc].v);
                    loc++;
                }
                res[q[i].id]=ans;
            }
            REP(i,1,k){
                printf("%lld
    ",res[i]);
            }
        }
    }
  • 相关阅读:
    SSM-网站后台管理系统制作(4)---Ajax前后端交互
    SSM-网站后台管理系统制作(3)---Google的reCaptcha验证码
    SSM-网站后台管理系统制作(2)---SSM基本工作原理
    SSM-网站后台管理系统制作(1)
    编译原理(龙书)-编译器制作
    Linux相关代码
    Python制作AI贪吃蛇
    S-DES算法实现(C++版本)
    照片收藏
    Python-制作抖音图片
  • 原文地址:https://www.cnblogs.com/00isok/p/10915386.html
Copyright © 2020-2023  润新知