随笔分类 -  并查集

摘要:按边从小到大排序。对于每条边(from, to, dist),如果from和to在同一个集合中,那么这条边无意义,因为之前肯定有比它更小的边连接了from和to。如果from和to不属于同一个集合,那么增加这条边后增加的点对数目是cnt[from]*cnt[to]*2( 因为(u, v)和(v, u)不算同一点对,所以*2 )统计出所有点对数total。对于查询,按t值从小到大排序,边从小到大一条一条往里加。tmpSum为f值小于t的点对总数。当边权大于等于t值时:ans[i] = total - tmpSum。当边权小于t值时,更新tmpSum。#include #include #incl 阅读全文
posted @ 2013-09-26 21:09 冰鸮 阅读(209) 评论(0) 推荐(0)
摘要:方法参见:http://blog.acmol.com/?p=751从最后一个线段开始倒着处理(因为之后的线段不会被它之前的线段覆盖),把这条线段所覆盖的所有线段编号合并到一个集合里,并以最左边线段编号为父结点。然后,以后的线段每次都是从右端向左端进行以下处理:1、判断该线段在并查集中的根结点是否被覆盖过(用一个数组标记),如果没有被覆盖,则将该线段所在集合与海报左端点所在集合进行合并(以左端点所在集合为根)。2、然后开始处理刚处理过的线段父结点左边的那一个线段,处理方法与第1步时一样。3、直到要处理的线段在左端点的左边时停止循环。处理时,如果有一个线段未被覆盖,就证明该点的染色没有被之后的染色 阅读全文
posted @ 2013-09-17 22:17 冰鸮 阅读(528) 评论(0) 推荐(0)
摘要:思路跟 LA 6187 完全一样。我是乍一看没反应过来这是个并查集,知道之后就好做了。d[i]代表节点 i 到根节点的距离,即每次的sum。 1 #include 2 #include 3 #include 4 5 const int MAXN = 200010; 6 7 int N, Q; 8 int p[MAXN]; 9 int d[MAXN];10 11 int FindSet( int x )12 {13 if ( p[x] == x ) return x;14 int root = FindSet( p[x] );15 d[x] += d[ p[x]... 阅读全文
posted @ 2013-07-19 22:39 冰鸮 阅读(165) 评论(0) 推荐(0)
摘要:只有一个地方需要注意:设节点a的根为u,b的跟为v,则:a = u + d[a]; b = v + d[b];已知:b-a=w。所以v - u = d[a] - d[b] + w;在合并两个集合修改根节点时,把v的根改为u,同时v到根的距离为d[a] - d[b] + w; 1 #include 2 #include 3 4 const int MAXN = 100010; 5 6 int pa[MAXN]; 7 long long int d[MAXN]; 8 9 int findset( int x )10 {11 if ( pa[x] == x ) return x;1... 阅读全文
posted @ 2013-07-15 17:31 冰鸮 阅读(322) 评论(0) 推荐(0)
摘要:题目链接:http://livearchive.onlinejudge.org/external/59/5914.pdf分析:并查集。相同祖先的放入同一个集合,每个集合可能有一个ID编号,也可能没有。如果最后存在两个集合的ID为确定值且不相同,那么NO如果最后所有集合都没有ID编号,或者只剩两个集合,一个有编号,一个没编号,那么POSSIBLY如果最后所有的集合ID编号相同,或者只剩下一个集合,那么YES 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 5 const int M 阅读全文
posted @ 2012-08-15 20:24 冰鸮 阅读(217) 评论(0) 推荐(0)