并查集 || [USACO18JAN]MooTube || BZOJ 5188 || Luogu P4185

题面:[USACO18JAN]MooTube

题解:

对边和询问都排序,然后每次把符合当前要求的边都扔并查集里,对于每个询问判断当前并查集里节点数即可。

我很无聊地给并查集加了按秩排序,还开了O2,加了快读,也才170ms,虽然在第一面,然鹅还是没有办法排太前。

上述操作都不做也行

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 inline int rd(){
 5     int x=0; char c=getchar();
 6     while(c<'0'||c>'9')c=getchar();
 7     while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
 8     return x;
 9 }
10 const int maxn=1e5+5,maxq=1e5+5;
11 int N,Q,a,b,c,fa[maxn],dep[maxn],f1,f2,now,cnt[maxn],ans[maxq];
12 struct Edge{ int from,to,dis; }edge[maxn];
13 struct Query_{ int k,x,id; }qry[maxq];
14 inline bool cmp1(const Edge&a,const Edge&b){ return a.dis>b.dis; }
15 inline bool cmp2(const Query_&a,const Query_&b){ return a.k>b.k; }
16 inline int getf(int a){
17     if(fa[a]==a) return a;
18     fa[a]=getf(fa[a]);
19     return fa[a];
20 }
21 int main(){
22     scanf("%d%d",&N,&Q);
23     for(int i=1;i<N;i++){
24         a=rd(); b=rd(); c=rd();
25         edge[i].from=a;
26         edge[i].to=b;
27         edge[i].dis=c;
28     }
29     for(int i=1;i<=Q;i++){
30         a=rd(); b=rd();
31         qry[i].k=a; qry[i].x=b; qry[i].id=i;
32     }
33     sort(edge+1,edge+N,cmp1);
34     sort(qry+1,qry+Q+1,cmp2);
35     for(int i=1;i<=N;i++) fa[i]=i,cnt[i]=1;
36     now=0;
37     for(int i=1;i<=Q;i++){
38         while(now+1<=N-1 && edge[now+1].dis>=qry[i].k){
39             now++;
40             f1=getf(edge[now].from);
41             f2=getf(edge[now].to);
42             if(f1!=f2){
43                 if(dep[f1]<dep[f2]){
44                     fa[f1]=f2;
45                     cnt[f2]+=cnt[f1];
46                 }
47                 else if(dep[f1]>dep[f2]){
48                     fa[f2]=f1;
49                     cnt[f1]+=cnt[f2];
50                 }
51                 else{
52                     fa[f1]=f2;
53                     dep[f2]++;
54                     cnt[f2]+=cnt[f1];
55                 }
56             }
57         }
58         ans[qry[i].id]=cnt[getf(qry[i].x)]-1;
59     }
60     for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
61     return 0;
62 }
View Code

 


By:AlenaNuna

 

转载于:https://www.cnblogs.com/AlenaNuna/p/11604583.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值