[USACO18JAN]MooTube G

题目 【并查集】

思路

  • >=k即符合条件的边才给它合并,这样的话这个连通块中所有的点都符合条件啦
  • 每次询问都重新合并一次的话会超时
  • 用到两个快排,把每条边从大到小排,再把询问的k从大到小排
  • 先做最大的k,把符合条件的点合并后,那么下一个k肯定比这个小啦
  • 那么符合大k的点肯定符合小k的点啦,那么就不用再重复合并啦

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
int p[N], num[N], ans[N];

int n, q;
struct E{
    int a,b,w;
    bool operator<(const E& t) {
        return w>t.w;
    }
}e[N];

struct Q{
    int k,v,i;
    bool operator<(const Q& t) {
        return k>t.k;
    }
}query[N];

int find(int x) {
    if(x != p[x]) p[x] = find(p[x]);
    return p[x];
}

void merge(int a, int b) {
    int pa=find(a), pb=find(b);
    if(pa != pb) {
        p[pa] = pb;
        num[pb] += num[pa];
    }
}

int main()
{
    cin>>n>>q;
    for(int i=0; i<N; ++i) {
        p[i] = i;
        num[i] = 1;
    }
    for(int i=0; i<n-1; ++i) {
        int a,b,w;
        scanf("%d%d%d", &a, &b, &w);
        e[i] = {a,b,w};
    }
    for(int i=0; i<q; ++i) {
        int k,v;
        scanf("%d%d", &k, &v);
        query[i] = {k,v,i};
    }
    //
    sort(e,e+n-1);
    sort(query,query+q);
    
    int j=0;
    for(int i=0; i<q; ++i) {
        auto& qq=query[i];
        while(j<n-1 && e[j].w >= qq.k) {//valid merge
            merge(e[j].a, e[j].b);
            j++;
        }
        ans[qq.i] = num[find(qq.v)];
    }
    for(int i=0; i<q; ++i) {
        printf("%d\n", ans[i]-1);
    }
    return 0;
}
posted @ 2021-08-18 21:54  misaka-mikoto  阅读(46)  评论(0编辑  收藏  举报