洛谷P4185 [USACO18JAN]MooTube G 题解

洛谷P4185 [USACO18JAN]MooTube G 题解

题目链接:P4185 [USACO18JAN]MooTube G

题意

给出一棵无根树, m ≤ 1 0 5 m \le 10^5 m105 次询问,给出 k , v k,v k,v ,询问共有多少结点 u u u 满足 u u u v v v 的路径上最小边权不小于 k k k

考虑把所有相互满足条件的结点用并查集合并

注意到当 k k k 减小时,合并后的连通块数量单调递减

考虑将询问按 k k k 降序排序,离线处理

每次去找没合并过的边显然太麻烦

继续利用单调性,将所有边按边权降序排序

这样我们扫一遍就能处理所有询问了

复杂度瓶颈在于排序。

时间复杂度 O ( m log ⁡ m ) O(m \log m) O(mlogm)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e5+15)

struct Edge {int u,v,w;}e[N];
struct Query{int k,v,id;}q[N];
int n,m,f[N],sz[N],ans[N];
void init(int n){for(int i=1; i<=n; i++) f[i]=i,sz[i]=1;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(int u,int v)
{
    u=find(u);v=find(v);
    f[u]=v;
    sz[v]+=sz[u];
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m;
    init(n);
    for(int i=1; i<n; i++)
        cin >> e[i].u >> e[i].v >> e[i].w;
    for(int i=1; i<=m; i++)
        cin >> q[i].k >> q[i].v,q[i].id=i;
    sort(e+1,e+1+n,[](Edge a,Edge b){return a.w>b.w;});
    sort(q+1,q+1+m,[](Query a,Query b){return a.k>b.k;});
    for(int i=1,j=1; i<=m; i++)
    {
        for(; j<=n&&q[i].k<=e[j].w; j++)
            merge(e[j].u,e[j].v);
        ans[q[i].id]=sz[find(q[i].v)]-1;
    }
    for(int i=1; i<=m; i++)
        cout << ans[i] << '\n';
    return 0;
}

转载请说明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值