P4185 [USACO18JAN] MooTube G 題解

mountzhu發表於2024-09-18

水一篇題解。
也是一道並查集的好題,涉及另一個並查集的基本應用,並查集維護連通塊(我跟並查集過不去了???)
大致題意:
給你一棵樹,對於每次詢問求一個點所在連通塊中到達該點的最小路徑權值大於給定值的點個數。

既然都連通塊了,那我們在維護連通塊的時候直接不把權值大於K的邊加進去,用並查集維護,按秩合併,答案就是連通塊大小減一。
但是考慮對於每次詢問都重新操作顯然是不行的,所以離線下來按K排序。
Code:

#include<bits/stdc++.h>
using namespace std;
int n,q,fa[100005],siz[100005],x,y;
struct Edge{
    int u,v,val;
}edge[100005];
struct Quest{
    int k,wh,id,ans;
}quest[100005];
bool cmp(Edge a,Edge b){
    return a.val>b.val;
}
bool cmpq(Quest a,Quest b){
    return a.k>b.k;
}
bool cmqp(Quest a,Quest b){
    return a.id<b.id;
}
int find(int x){
    if(fa[x]==x) return x;
    else return fa[x]=find(fa[x]);
}
int main(){
    scanf("%d %d",&n,&q);
    for(int i=1;i<=n-1;++i) scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].val);
    for(int i=1;i<=q;++i) scanf("%d %d",&quest[i].k,&quest[i].wh),quest[i].id=i;
    sort(edge+1,edge+n,cmp);
    sort(quest+1,quest+q+1,cmpq);
    for(int i=1;i<=n;++i) siz[i]=1,fa[i]=i;
    int j=1;
    for(int i=1;i<=q;++i){
        for(j;edge[j].val>=quest[i].k&&j<n;++j){
        	x=find(edge[j].u),y=find(edge[j].v);
            if(x!=y){
            	fa[x]=y;
            	siz[y]+=siz[x];
			} 
        }
        quest[i].ans=siz[find(quest[i].wh)]-1;
    }
    sort(quest+1,quest+q+1,cmqp);
    for(int i=1;i<=q;++i) printf("%d\n",quest[i].ans);
    return 0;
}

相關文章