并查集

并查集 --以cogs259为例

我怕爱的太早我们不能终老 提交于 2019-12-01 23:20:26
题目链接: http://cogs.pro:8081/cogs/problem/problem.php?pid=pySmxSVgP 【问题描述 】 或许你并不知道,你的某个朋友是你的亲戚。他可能是你的曾祖父的外公的女婿的外甥女的表姐的孙子。如果能得到完整的家谱,判断两个人是否是亲戚应该是可行的,但如果两个人的最近公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系实非人力所能及。在这种情况下,最好的帮手是计算机。 为了将问题简化,你将得到一些亲戚关系的信息,如同Xuebin和Grant是亲戚,Grant和Tension是亲戚等,从这些信息中,你可以推出xuebin和Tension是亲戚。请写一个程序,对于我们的关于亲戚关系的提问,以最快的速度给出答案。 【输入格式】 输入由两部分组成: 第一部分以N、M开始。N为问题涉及到的人的个数(1<N<20000)。这些人的编号为1、2、3、…、N。下面有M行(1<M<1000000),每行有两个数ai、bi,表示已知ai和bi是亲戚。 第二部分以Q开始。以下Q行有Q个询问(1<Q<1000000),每行为ci、di,表示询问ci和di是否为亲戚。 【输出格式】 输出有若干行, 对于每个询问ci、di,若ci和di为亲戚,则输出Yes,否则输出No。 【输入输出样例】 输入文件 10 7 2 4 5 7 1 3 8 9 1 2 5 6

【提高组】并查集

送分小仙女□ 提交于 2019-12-01 23:14:38
(时隔多日回归刷题日常...) P1111 修复公路 按时间sort一遍,每次合并两个节点,显然如果原先不连通那么合并之后联通块数量--。然后如果n==1就输出当前时间return。 #include<bits/stdc++.h> #define For(i,l,r) for(int i=l;i<=r;i++) using namespace std; const int M=2e5+5; struct node{ int x,y,t; }e[M]; int fa[M],n,m; inline int cmp(const node x,const node y){return x.t<y.t;} inline int getfa(int x){return fa[x]==x?x:getfa(fa[x]);} inline int read(){ int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();} return f*sum; } int main(){ n=read(),m=read(); For(i,1,m) e[i].x=read(),e

Codeforces 516D

柔情痞子 提交于 2019-12-01 22:32:37
原题链接 题意 给定一棵大小为 \(n\) ,带边权的树,定义 \(f(i)\) 为 \(i\) 与其它点的距离最大值。 \(m\) 组询问,每次询问给定 \(g\) ,求最大的联通块大小,该联通块满足各点的 \(f(i)\) 的极差不超过 \(g\) 。 \(1 \leq n \leq 10 ^5 , 1 \leq m \leq 100\) 。各边边权、 \(g\) 大小在 \(int\) 范围内。 题解 考场上我是这么想的,首先将 \(f(i)\) 单独求出,仅将其看作普通的独立点权。将各点按照 \(f\) 值从小到大排序,从小到大枚举 \(f\) 值最小的点 \(i\) ,则一路扫过去, \(f(i) + g \leq f(j)\) 的点都可取;随着 \(i\) 的右移, \(j\) 也单调右移。指针的移动过程复杂度是 \(O(n)\) 的,问题在于如何快速地求解当前情况下的最大联通块大小。 考虑 动态维护 联通块大小。加点时维护联通块大小,并不难办,用并查集即可。然而随着 \(i\) 的右移,我们会删点,删点就会影响整个联通块的连通性,即可能将原联通块分裂成若干小块。这样一来,并查集无法维护,怎么做? 实际上,我将 \(f(i)\) 的本质跟所求完全割裂开来的想法不够妥当,这样就无法利用 \(f(i)\) 本身的性质进行求解。 一种不错的思路是设计一种删点的顺序

Luogu P2342 叠积木 加权并查集

笑着哭i 提交于 2019-12-01 13:46:06
可能这是一类题目吧,这道题比较典型,可以当作模板。 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 const int Maxn = 30030; 6 7 int fa[Maxn],d[Maxn],size[Maxn]; 8 int find(int x){ 9 if(fa[x] == x)return x; 10 int rt = find(fa[x]); 11 d[x] += d[fa[x]]; 12 return fa[x] = rt; 13 } 14 15 void merge(int x,int y){ 16 x = find(x),y = find(y); 17 if(x != y){ 18 fa[x] = y; 19 d[x] = size[y],size[y] += size[x]; 20 } 21 } 22 23 int p,x,y; 24 char ch; 25 26 int main(){ 27 for(int i = 1;i <= 30000;i++)fa[i] = i,size[i] = 1,d[i] = 0; 28 cin >> p; 29 while(p--){ 30 cin >> ch; 31 if(ch == 'C'){ 32 cin >> x; 33 find

hihocoder 1066 并查集

拥有回忆 提交于 2019-12-01 08:50:37
/**/ #include <cstdio> #include <cstring> #include <cmath> #include <cctype> #include <iostream> #include <algorithm> #include <map> #include <set> #include <vector> #include <string> #include <stack> #include <queue> typedef long long LL; typedef unsigned long long ULL; using namespace std; bool Sqrt(LL n) { return (LL)sqrt(n) * sqrt(n) == n; } const double PI = acos(-1.0), ESP = 1e-10; const LL INF = 99999999999999; const int inf = 999999999, N = 1e5 + 5; int n, op, fa[N], m, x, y; char s[N]; map<string, int> mp; int Find(int x) { int y = x; for(; x != fa[x]; x = fa[x]); return fa[y] = x; }

SPF POJ - 1523 割点+并查集

浪子不回头ぞ 提交于 2019-12-01 07:09:16
题意: 问你这个图中哪个点是割点,如果把这个点去掉会有几个子网 代码: 1 //给你几个点,用着几个点形成了一个图。输入边形成的图,问你这个图中有多少个割点。每一个割点去掉后会形成几个强连通分量 2 //方法: 3 //你可以想用tarjan算法求出来谁是割点。然后每一个割点单独用并查集判断。用所有边(不和这个割点相连的边)通过并查集判断一下 4 //然合并后有几个区域就可以了 5 #include<stdio.h> 6 #include<string.h> 7 #include<algorithm> 8 using namespace std; 9 const int spot=1010; 10 const int edge=500010; 11 struct node 12 { 13 int u,v; 14 }m[edge]; 15 struct stu 16 { 17 int to,next; 18 } a[edge]; 19 int head[spot],fa,low[spot],num[spot],root,indexx,sizes,flag1,n,fx[spot],qua,len,v[spot]; //fx指祖节点 20 bool flag[spot],flag2[spot],b[spot],have[spot]; 21 void init() 22 { 23

10月清北学堂培训 Day 2

杀马特。学长 韩版系。学妹 提交于 2019-12-01 02:52:27
今天是杨溢鑫老师的讲授~ T1 物理题,不多说(其实是我物理不好qwq),注意考虑所有的情况,再就是公式要推对! #include<bits/stdc++.h> using namespace std; typedef long long LL; const LL mod = 998244353; inline void rd(LL &x) { x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} } LL n,m,x[2],y[2],g,ans; LL qpow(LL a) { LL res=1,k=mod-2; while(k) { if(k&1)res=res*a%mod; a=a*a%mod; k>>=1; } return res; } LL _2 = qpow(2); void down(LL x,LL h){x%=mod;h%=mod; ans += (x*x*m%mod)*qpow(4*h); ans%=mod;} void up(LL x,LL h) {x%=mod;h%=mod; ans += (m*h%mod) + ( (x*x*m%mod)

10.9

与世无争的帅哥 提交于 2019-11-30 23:31:44
1,P1330 关于黑白染色法 (1)必须要有两个数组 int cnt[2],一个代表黑色的计数,一个代表白色的计数。 int color[1000010]代表每个点的颜色。 (2)染色机制 color[v]=(color[u]+1)%2; color[u]表示一个染色(0或者1) color[v]是相邻的染色。 关于合并多个联通图。(如果图是不连通的话) memset(cnt,0,sizeof(cnt)); if(color[i]==-1) { color[i]=1; ans+=dfs(i) } 结构很好 2,P2661 一,首先这个东西跟封锁阳光校园一样让我更加明确了图的性质。 比如阳光校园让我明确了有向和联通的概念。 那么这个传递信息则让我明确了自环,和入度的概念。 然后求最小环。。看了那么多还是得用并查集。 然后看了并查集。 只是浅显地了解了一下并查集! 涉及到了找根节点和联合。 先放着 来源: https://www.cnblogs.com/beiyueya/p/11644659.html

19十一高端峰会——成都站

早过忘川 提交于 2019-11-30 22:00:32
T2 修建马路 并查集 注意到直接维护连通性不好做,因为我们在图上不断地删点,而并查集不支持删除操作。 考虑转化问题,瞬移能力相当于把整张图复制一份,我们注意到无法通行当且仅当被删除的方格围成了一个八连通的环。 用可撤销并查集维护 能够证明必须围成一个环,也就是如果超出边界要瞬移到图的另一边,特殊数据如下 4 6 17 3 3 1 6 4 6 2 4 4 5 4 4 1 4 3 4 1 2 3 1 2 3 1 3 3 2 4 3 1 1 2 2 2 6 来源: https://www.cnblogs.com/White-star/p/11642045.html

【模板】并查集

半腔热情 提交于 2019-11-30 21:41:09
1 const int maxn = 100010; 2 int fa[maxn]; 3 4 int find(int x) 5 { 6 if (fa[x] == x) return x; 7 fa[x] = find(fa[x]); 8 return fa[x]; 9 } 10 11 void merge(int a, int b) 12 { 13 fa[find(a)] = find(b); 14 } 15 16 bool check(int a, int b) 17 { 18 return find(a) == find(b); 19 } 来源: https://www.cnblogs.com/thjkhdf12/p/11641409.html