P4185 [USACO18JAN]MooTube


这个题想了我2天,最后实在忍不住瞟了一眼题解,看到并查集三个字,一下就明白了。
还是利用离线 + 答案单调性的思想。不难发现,假如询问的\(k\)单调递减,那么答案一定单调递增。
所以考虑离线。将询问排序以后,每次将满足条件的边(即满足\(k \leq val\)的边)连上,答案就是点所在连通块的大小。

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 20;
inline int read()
{
    int x = 0; char ch = getchar(); bool f = false;
    while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    return f ? -x : x;
}

int N, Q;

struct edge
{
    int from, to, cost;
    inline bool operator <(const edge &rhs) const{
        return cost > rhs.cost;
    }
};vector<edge> g;
struct state
{
    int k, v, idx, res;
}ask[MAXN];

inline bool cmp1(state &lhs, state &rhs){
    return lhs.k > rhs.k; 
}
inline bool cmp2(state &lhs, state &rhs){
    return lhs.idx < rhs.idx;
}

namespace ufs
{
    int fa[MAXN], siz[MAXN];

    void init(){for(int i = 1; i <= N; i++) fa[i] = i, siz[i] = 1;}
    int findfa(int x){return fa[x] == x ? x : fa[x] = findfa(fa[x]);}
    void unite(int x, int y){x = findfa(x), y = findfa(y), siz[y] += siz[x], fa[x] = y;}
}

int main()
{
    cin>>N>>Q;
    for(int i = 1; i < N; i++){
        int u = read(), v = read(), c = read();
        g.push_back((edge){u, v, c});
    }
    for(int i = 1; i <= Q; i++){
        int k = read(), v = read();
        ask[i] = (state){k, v, i};
    }

    sort(ask + 1, ask + Q + 1, cmp1);
    sort(g.begin(), g.end());

    ufs::init(); vector<edge>::iterator it = g.begin();

    for(int i = 1; i <= Q; i++){
        while(it != g.end() && it->cost >= ask[i].k) ufs::unite(it->from, it->to), ++it;
        ask[i].res = ufs::siz[ufs::findfa(ask[i].v)];
    }
    
    sort(ask + 1, ask + Q + 1, cmp2);
    for(int i = 1; i <= Q; i++) printf("%d\n", ask[i].res - 1);
    return 0;
}

转载于:https://www.cnblogs.com/wsmrxc/p/9432848.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值