[USACO18JAN] MooTube (并查集 -> 维护连通性)

题目大意:给你一棵边权树,定义两点间距离为它们唯一路径上的最小路权,求与某点距离不大于K(k为已知)的点的数量

带权并查集维护集合内元素总数

路和问题 都按权值大到小排序,枚举问题, 建权值不小于K的边,并查集维护连通性,求集合元素内总数即可

 1 #include <bits/stdc++.h>
 2 #define N 200100
 3 #define inf 0x3f3f3f3f
 4 using namespace std;
 5
 6 int n,q,cnt;
 7 int fa[N],f[N];
 8 struct EDGE{
 9     int x,y,w;
10 }edge[N];
11 struct QUES{
12     int k,v,id,ans;
13 }ques[N];
14
15 int cmp1(EDGE s1,EDGE s2) {return s1.w>s2.w;}
16 int cmp2(QUES s1,QUES s2) {return s1.k>s2.k;}
17 int cmp3(QUES s1,QUES s2) {return s1.id<s2.id;}
18 void edge_add(int x,int y,int z)
19 {
20     cnt++;
21     edge[cnt].x=x;
22     edge[cnt].y=y;
23     edge[cnt].w=z;
24 }
25 int find_fa(int x)
26 {
27     int fx=x;
28     while(fx!=fa[fx]) {fx=fa[fx];}
29     while(fa[x]!=fx)
30     {
31         int pr=fa[x];
32         f[pr]-=f[x];
33         fa[x]=fx;
34         x=pr;
35     }
36     return fx;
37 }
38 void comb(int x,int y)
39 {
40     int fx=find_fa(x);
41     int fy=find_fa(y);
42     fa[fy]=fx;
43     f[fx]+=f[fy];
44 }
45
46 int main()
47 {
48     scanf("%d%d",&n,&q);
49     for(int i=1;i<n;i++)
50     {
51         int x,y,z;
52         scanf("%d%d%d",&x,&y,&z);
53         edge_add(x,y,z);
54     }
55     sort(edge+1,edge+n,cmp1);
56     for(int i=1;i<=q;i++)
57     {
58         int x,y;
59         scanf("%d%d",&x,&y);
60         ques[i].k=x;
61         ques[i].v=y;
62         ques[i].id=i;
63     }
64     sort(ques+1,ques+q+1,cmp2);
65     for(int i=1;i<=n;i++)
66     {
67         fa[i]=i;
68         f[i]=1;
69     }
70     int j=1;
71     for(int i=1;i<=q;i++)
72     {
73         while(edge[j].w>=ques[i].k)
74         {
75             comb(edge[j].x,edge[j].y);
76             j++;
77         }
78         int fv=find_fa(ques[i].v);
79         ques[i].ans=f[fv]-1;
80     }
81     sort(ques+1,ques+q+1,cmp3);
82     for(int i=1;i<=q;i++)
83     {
84         printf("%d\n",ques[i].ans);
85     }
86     return 0;
87 }

原文地址:https://www.cnblogs.com/guapisolo/p/9696881.html

时间: 2024-08-01 05:01:04

[USACO18JAN] MooTube (并查集 -> 维护连通性)的相关文章

【luogu4185】 [USACO18JAN]MooTube [并查集]

P4185 [USACO18JAN]MooTube 并查集好合并不好拆开 可以考虑离线 先读入 从大到小排序 再依次合并 技巧:不好断开就倒着来合并 JSOI2008 P1197 也是该思想 #include<bits/stdc++.h> using namespace std; #define Max(x,y) (x)<(y)?(y):(x) #define Min(x,y) (x)<(y)?(x):(y) #define ll long long #define rg regi

nyoj 单词拼接(并查集判断连通性+欧拉路径)

这题还是比较难的. 首先建图方面,如果单纯的把单词作为点,能拼接的关系作为边,那么就是哈密顿图(每个点仅能走一次),难度比较大. 换一种思路,就是把每个单词看成一条有向边,由该单词的首字母指向尾字母. 那么这题便是欧拉图的问题了. 本质上采用的还是搜索,但是为了快速得到字典序最小的欧拉路径,首先要对单词集进行排序. 排完序后,用边集数组存图:再通过计算各点的出度与入度,同时判断基图(不考虑边的方向的图)的连通性,判断是否存在欧拉回路或欧拉通路. 如果存在欧拉回路,那么就从0开始搜索: 如果存在欧

[Codeforces 1027 F] Session in BSU [并查集维护二分图匹配问题]

题面 传送门 思路 真是一道神奇的题目呢 题目本身可以转化为二分图匹配问题,要求右半部分选择的点的最大编号最小的一组完美匹配 注意到这里左边半部分有一个性质:每个点恰好连出两条边到右半部分 那么我们可以利用这个性质 考虑一个左边的点和它右边联通的两个点,发现这两个点只能选择一个和这个左边的点匹配 那么我们考虑把这个点点匹配的模型转化成点边匹配 我们在同一个左边点连的两个右边点之间连边,那么问题就变成了一个点和一条相邻的边匹配,求完美匹配的问题了 而这个问题,我们显然可以用并查集来很好的解决 考虑

poj 1456 Supermarket(并查集维护区间)

 题意:有一些货物,每个货物有价值和卖出的截至日期,每天可以卖一个货物,问能卖出的最大价值是多少. 思路:算法不难想到,按价值降序排列,对于每一件货物,从deadline那天开始考虑,如果哪天空闲那么将货物在该天卖出. 如果直接暴力来做,复杂度为o(n*n),显然不行.可以用并查集来维护当前ddl之前空闲的最近的一天,如果父节点为0说明deadline之前没有空闲的时间,那么该货物就无法卖出. #include<cstdio> #include<cstring> #includ

The Suspects(并查集维护根节点信息)

The Suspects Time Limit: 1000MS   Memory Limit: 20000K Total Submissions: 37090   Accepted: 17980 Description Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. T

猴子大王Monkey King 左偏树+并查集维护

Description Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can't avoid quarrelling, and it only happens between two monkeys who does not know e

【模板/经典题型】并查集维护生成树

这里的并查集是按秩合并并查集. 这种方法维护生成树的时候可以维护一个点到根的权值. 但是由于合并的时候做了一个类似换根一样的操作,因此这个权值通常只能是异或之类的. //find-union-set int top,f[N],v[N],sz[N],sk[M]; int find(int x){return x==f[x]?f[x]:find(f[x]);} int value(int x){return x==f[x]?0:v[x]^value(f[x]);} bool merge(int a,

hdu 5424 回溯+并查集判断连通性

题意:给定一个n个点n条边的无向图,判断是否存在哈密顿路径. 思路:先用并查集判断图是否连通,然后从度数最小的点开始回溯,看是否能找到一条哈密顿路径. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <set> 5 using namespace std; 6 7 const int INF = 999999; 8 const int N = 1001; 9

[USACO18OPEN] Multiplayer Moo (并查集+维护并查集技巧)

题目大意:给你一个N*N的棋盘,棋盘上每个点都有一个权值 第一问求一个权值形成的最大联通块中点的数量 第一问求两个权值共同形成的最大联通块中点的数量 提供一种并查集的做法:(感谢大佬们的题解)第一问把所有相同权值的相邻的点用带权并查集合并一下就OK了 第二问,就需要一些骚操作了 我们的目的是把两个不同权值的所有联通块合并,再去看它们共同形成的最大联通块的大小 可以用一个结构体记录两个联通块之间的关系 分别是两个联通块的标号(即这个联通块构成的并查集的祖先节点) 以及这两个联通块的颜色 而为了简化