码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces1213G Path Queries 并查集

时间:2019-10-24 00:40:42      阅读:133      评论:0      收藏:0      [点我收藏+]

标签:+=   path   pre   lin   code   并查集   span   printf   opera   

题意

给定n个结点的树,每条边有边权,有m个询问,每个询问给一个\(q_i\)输出树上有多少点对的简单路径上最大的边权不超过\(q_i\)

分析

用并查集维护点集,同时维护大小。

将所有边按边权排序,考虑每次从小到大加边,图中经过当前边的所有路径一定是以当前边的边权为最大值的,用并查集维护下图中每个联通块的大小,经过当前边的路径数即为\(sz[find(u)]*sz[find(v)]\)。然后前缀和一下就可以\(O(1)\)询问了。

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define pb push_back
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=2e5+10;
int n,m;
int f[maxn];
ll ans[maxn],sz[maxn];
int find(int k){
    if(k==f[k]) return k;
    else return f[k]=find(f[k]);
}
struct ppo{
    int u,v,w;
    bool operator<(const ppo &r) const{
        return w<r.w;
    }
}a[maxn];
int main(){
    //ios::sync_with_stdio(false);
    //freopen("in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) f[i]=i,sz[i]=1;
    for(int i=1;i<n;i++){
        scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
    }
    sort(a+1,a+n);
    for(int i=1;i<n;i++){
        int rx=find(a[i].u),ry=find(a[i].v);
        ans[a[i].w]+=sz[rx]*sz[ry];
        f[rx]=ry;
        sz[ry]+=sz[rx];
    }
    for(int i=1;i<=2e5;i++) ans[i]+=ans[i-1];
    while(m--){
        int x;scanf("%d",&x);
        printf("%lld ",ans[x]);
    }
    return 0;
}

codeforces1213G Path Queries 并查集

标签:+=   path   pre   lin   code   并查集   span   printf   opera   

原文地址:https://www.cnblogs.com/xyq0220/p/11729564.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!