并查集

ZROI 19.08.03 分治与离线

回眸只為那壹抹淺笑 提交于 2019-11-27 20:30:01
经典问题,给一张图,支持加边/删边/询问两点连通性。 离线统计边权(删除时间),lct维护最大生成树即可。 也可以按时间分治,维护一个可回退并查集即可。 主定理 很好用,但是记不住。 有一种简明的替代方式:画一棵递归树,考虑层数和每层的节点数(线段树分析.jpg) 分治时递归和处理中心的顺序可以是任意的,可以按照具体情况选择,以 简化复杂度。 快速排序的期望复杂度: \[T(n)=\frac{1}{n}\sum_{i=1}^n[T(i-1)+T(n-i)]+n-1=\frac{2}{n}\sum_{i=0}^{n-1}T(i)+n-1\] \[n\cdot T(n)=2\sum_{i=0}^{n-1}T(i)+n(n-1)\] \[(n-1)\cdot T(n-1)=2\sum_{i=0}^{n-2}T(i)+(n-1)(n-2)\] \[n\cdot T(n)-(n-1)\cdot T(n-1)=2T(n-1)+2(n-1)\] \[n\cdot T(n)=(n+1)T(n-1)+2(n-1)\] \[\frac{T(n)}{n+1}=\frac{T(n-1)}{n}+\frac{2(n-1)}{n(n+1)}\] \[F(n)=\frac{T(n)}{n+1}=\sum_i^n\frac{2(i-1)}{i(i+1)}\leq \sum_i^n \frac{2}{i}=2\ln

【JSOI2008】星球大战[并查集]

两盒软妹~` 提交于 2019-11-27 20:24:40
[JSOI2008]星球大战 决定再做一道并查集水题.... 正难则反 现将要攻击的星球都读入 然后记录已损坏 再将能连的都连上 然后倒着做 就是套路了QAQ 第一次交的代码死于没有认真读题...编号是 从0开始 的 #include<bits/stdc++.h> using namespace std; const int N=4e5+5,M=2e5+5,inf=0x3f3f3f3f,P=19650827; int n,m,k,cnt=0,ans[N],a[N]; bool broken[N]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } int head[N],tot=0; struct edge{int v,nxt;}e[M<<1]; void add(int u,int v){ e[++tot]=(edge){v,head[u]},head[u]=tot; } int f[N]; int find(int x){return f[x]==x?x:f[x]=find(f[x]);}

并查集

拥有回忆 提交于 2019-11-27 19:13:20
一、鄙人的浅薄认知:给你一些具有父子关系的数据,你的任务就是把他们家家谱汇总出来,然后,顺便记录一些年龄啊,几个孩子什么的,最后回答问题就行了。 二、典型例题 1、HDU 1232 畅通工程 http://acm.hdu.edu.cn/showproblem.php?pid=1232 这道题是大多数人的入门题。 题解:有好多村子,现在已经建了一些路了,问还要建多少才能让所有的村子相通。 首先至少ans = n - 1条,如果目前互不认识。然后建立父子关系,不是一个祖宗的给他们建了路了,父子关系成立,他们成为一家子了,ans 自然 - 1。 是一个祖宗的本来就是一家子,不用管。然后一直这样判断直到读入结束。 代码: 1 #include<iostream> 2 #include<cstring> 3 #include<queue> 4 using namespace std; 5 const int N = 1010; 6 int father[N]; 7 8 int Find(int x) { 9 if (father[x] == x) return x; 10 return father[x] = Find(father[x]); 11 } 12 13 int main() 14 { 15 int n, m; 16 while (scanf("%d", &n) && n) {

SP5150 JMFILTER - Junk-Mail Filte(并查集)

 ̄綄美尐妖づ 提交于 2019-11-27 18:36:24
直秒并查集。这题的难点就在于怎么删点。如果要删的是叶节点,那还好,直接刨掉即可 如果是中间节点甚至是根节点,那就不好办了..... solution: 对于独立一个点,我可以用邻接表模拟,然后用并查集维护联通,删点就是普通删点,但是实现难度高,复杂度大,算了,还是想正解吧 正解:对于一个删了的点,我们打个标记,然后开一个新点表示这个点(居然有点像主席树233.....) 于是, 动态开点并查集 诞生了(口胡) 具体操作在代码里解释 代码: #include<bits/stdc++.h> using namespace std; const int maxn=2e6+9; int n,m,ans,vis[maxn],fa[maxn],d[maxn],cnt; int T; int find(int x)//普普通通的并查集 { if(fa[x]==x) return x; return fa[x]=find(fa[x]); } void mergy(int x,int y)//普普通通的合并 { int fx=find(x); int fy=find(y); if(fx!=fy) fa[fx]=fy; } void del()//普普通通的清零(多组数据) { memset(vis,0,sizeof(vis)); ans=0; n=0,m=0; } int main() {

[bzoj4025] 二分图

淺唱寂寞╮ 提交于 2019-11-27 18:20:59
Description 神犇有一个 \(n\) 个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。 Input 输入数据的第一行是三个整数 \(n\) , \(m\) , \(T\) 。 第2行到第 \(m+1\) 行,每行 4 个整数 \(u\) , \(v\) , \(start\) , \(end\) 。第 \(i+1\) 行的四个整数表示第 \(i\) 条边连接 \(u\) , \(v\) 两个点,这条边在 \(start\) 时刻出现,在第 \(end\) 时刻消失。 Output 输出包含 \(T\) 行。在第i行中,如果第 \(i\) 时间段内这个图是二分图,那么输出 “ \(Yes\) ”,否则输出“ \(No\) ”,不含引号。 Sample Input 3 3 3 1 2 0 2 2 3 0 3 1 3 1 2 Sample Output Yes No Yes HINT 样例说明: 0时刻,出现两条边1-2和2-3。 第1时间段内,这个图是二分图,输出 \(Yes\) 。 1时刻,出现一条边1-3。 第2时间段内,这个图不是二分图,输出 \(No\) 。 2时刻,1-2和1-3两条边消失。 第3时间段内,只有一条边2-3,这个图是二分图,输出 \(Yes\) 。

hdu1878 欧拉回路 并查集

送分小仙女□ 提交于 2019-11-27 18:03:27
Problem Description 欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路? Input 测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结 束。 Output 每个测试用例的输出占一行,若欧拉回路存在则输出1,否则输出0。 Sample Input 3 3 1 2 1 3 2 3 3 2 1 2 2 3 0 Sample Output 1 0 欧拉回路: 无向图连通图的判断条件 --->> 所有点的度为偶数       有向图连通图的判断条件 --->> 出度+1,入度-1,所有点的度为0 欧拉路径: 无向图连通图的判断条件 --->> ① 所有点的度为偶数                     ② 其余点为偶数,有且仅有两个奇数度的点(一个为起点,一个为终点)       有向图连通图的判断条件 --->> ①出度+1,入度-1,所有点的度为0                     ②有且仅有两个点的度不为0,一个为1,一个为 -1 上述条件均需 一个大条件,图为连通图! 所以此题用并查集判断是否连通

可持久化并查集

白昼怎懂夜的黑 提交于 2019-11-27 16:50:50
模板题 可持久化就用主席树实现,学习自 这篇博客 #include<bits/stdc++.h> #define N 4000005 using namespace std; int read() { int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } int ndnum,n; int fa[N],lc[N],rc[N],dep[N],root[N]; void build(int k,int l,int r)//维护的是fa { if(l==r){fa[k]=l;return;} int mid=(l+r)>>1; build(lc[k]=++ndnum,l,mid); build(rc[k]=++ndnum,mid+1,r); } int query(int k,int L,int R,int pos) { if(L==R) return k; int mid=(L+R)>>1; if(pos<=mid)return query(lc[k],L,mid,pos); else return query(rc[k],mid+1,R,pos); } int

部落划分 (二分+并查集/kruskal)

旧街凉风 提交于 2019-11-27 16:47:21
问题: 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗。只是,这一切都成为谜团了——聪聪根本就不知道部落究竟是如何分布的。 不过好消息是,聪聪得到了一份荒岛的地图。地图上标注了N个野人居住的地点(可以看作是平面上的坐标)。我们知道,同一个部落的野人总是生活在附近。我们把两个部落的距离,定义为部落中距离最近的那两个居住点的距离。聪聪还获得了一个有意义的信息——这些野人总共被分为了K个部落!这真是个好消息。 聪聪希望从这些信息里挖掘出所有部落的详细信息。他正在尝试这样一种算法: 对于任意一种部落划分的方法,都能够求出两个部落之间的距离,聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离。 例如,下面的左图表示了一个好的划分,而右图则不是。请你编程帮助聪聪解决这个难题。 解: 再次明确几点重要的东西 别搞忘了 1:处理集合问题一定要用并查集 2: 最近的最远 最远的最近 不是二分就是生成树 考试的时候想到正解的 突然卡住 难受QWQ $1$ 二分一个最小距离 暴力枚举节点之间的距离,小于枚举的答案就合并成一个 集合                     两个部落的距离只会比这个更小所以必须合并 大于的话是另一个集合(考试的时候我就是在这里卡住了

食物链(并查集)

拈花ヽ惹草 提交于 2019-11-27 10:10:52
Problem Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类。 第二种说法是"2 X Y",表示X吃Y。 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 1) 当前的话与前面的某些真的话冲突,就是假话; 2) 当前的话中X或Y比N大,就是假话; 3) 当前的话表示X吃X,就是假话。 你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 Input 第一行是两个整数N和K,以一个空格分隔。 以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 若D=1,则表示X和Y是同类。 若D=2,则表示X吃Y。 Output 只有一个整数,表示假话的数目。 Sample Input 100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5 Sample Output 3 大概思路

【常用数据结构——并查集(又在乱牵线了)】

假装没事ソ 提交于 2019-11-27 08:17:50
并查集 简介    并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。   并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。(转自百度百科) 主要操作    众所周知,每个学校都有些奇怪的组织,有些是学校的,还有些''地下党''(咳咳,懂得),然后每个组织又分为了几个小组........当每年开学的那一天。总有些新面孔会来到这些组织,但是显然暂时不会。,这就意味着他们不属于任何一个组织 初始化 for(int i=1;i<=n;i++) f[i]=i;   几个月后,这些新同学陆陆续续的加入了组织,有一天,学校让所有的组织集合,这下好了,因为是新同学,所以他们只记得自己的上级,所以只能去找上级,好巧不巧,上级也只认识自己的上级(????)最后一大堆人浩浩荡荡地找到了组织长,愉快地集合了起来 查找 int