并查集专辑 (poj1182食物链,hdu3038, poj1733, poj1984, zoj3261)
并查集是一个树形的数据结构, 可以用来处理集合的问题, 也可以用来维护动态连通性,或者元素之间关系的传递(关系必须具有传递性才能有并查集来维护,因为并查集有压缩路径)。
用并查集来维护元素之间关系的传递, 那么元素与元素之间就有一个权值(带权并查集),那么当路径压缩时,我们需要根据关系的传递性来维护
当父元素变动时,关系的变动。
给定一些元素之间的关系, 问我们有多少是错误的。 当碰到一个错误时,并不会用它来更新并查集(错误的怎么用来更新?),只会把ans++
我们用0表示与父亲是同类, 用1表示吃父亲 , 用2表示被父亲吃。(这表示的是我与父亲的关系,即箭头是由我指向父亲), 那怎么得到父亲与我的关系呢?
只要将箭头的方向改变, 就得到了父亲与我的关系, (3-rank[x]) % 3 就是了
只要明白了箭头方向的改变,关系也可以用公式推导出来
那么下边就好办了, 如果判断是否发生错误呢?
如图,红色的线表示题目给我们的关系, 现在他们在一个集合里面,可以通过运算获得蓝线1,然后再通过计算获得蓝线2, 只要将蓝线2和红线对比,就知道
题目所给的关系是否正确。
同理,集合的合并也是一样的
通过红线1,依次算出蓝线1,2,3. 那么就可以进行集合的合并了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/*
路径压缩的时候要保留结点与结点之间的关系, 所以要维护的一个信息是,结点之间的关系
0同类 , 1被父亲吃, 2吃父亲
*/
const int N = + ;
int fa[N];
int id[N];//id[u] 表示与父亲之间的边的权值,, 权值为0,1,2三种
int find(int x)
{
if (x == fa[x])
return x;
//路径压缩的时候,由于父亲的改变, 需要改变权值
int tmp = fa[x];
fa[x] = find(fa[x]);
id[x] = (id[x] + id[tmp]) % ;
return fa[x];
}
int main()
{
int n, m, ans;
int d, a, b;
int fx, fy;
//while (scanf("%d%d", &n, &m) != EOF)
{
scanf("%d%d", &n, &m);
ans = ;
for (int i = ; i <= n; ++i)
{
fa[i] = i;
id[i] = ;
}
while (m--)
{
scanf("%d%d%d", &d, &a, &b);
if (d == )
{
if (a > n || b > n)
ans++;
else
{
fx = find(a);
fy = find(b);
if (fx != fy)
{
fa[fy] = fx;
id[fy] = (( - id[b])% + (d - ) + id[a]) % ;
}
else
{
if ((-id[a]+id[b])% != )
ans++; }
}
}
else
{
if (a > n || b > n)
ans++;
else
if (a == b)
ans++;
else
{
fx = find(a);
fy = find(b);
if (fx != fy)
{
fa[fy] = fx;
id[fy] = (( - id[b])% + (d - ) + id[a]) % ;
}
else
{
if (( - id[a] + id[b])% != )
ans++;
}
}
}
}
printf("%d\n", ans);
}
return ;
}
有连续的一段数,数字是什么谁都不知道, 但是呢有限制条件。
ai bi c 表示 下标ai到bi的这一段数的和为c
现在给我们m个限制条件,问我们有多少个限制条件与前面的条件矛盾
分析:依旧考察关系的传递, 只不过关系需要转换。 即 sum[bi] - sum[ai-1] = c
然后ai-1作为父亲, bi作为儿子, 权值为两者的差值。
其余的都和食物链那题差不多了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/*
给定一些约束条件, 问有多少个错误的
*/
const int N = + ;
int fa[N], r[N];
int find(int x)
{
if (x == fa[x])return x;
int f = fa[x];
fa[x] = find(fa[x]);
r[x] = r[x] + r[f];
return fa[x];
}
int main()
{
int n, m;
int a, b, fx, fy,w;
while (scanf("%d%d", &n, &m) != EOF)
{
for (int i = ; i <= n; ++i)
{
fa[i] = i;
r[i] = ;
}
int ans = ;
while (m--)
{
scanf("%d%d%d", &a, &b,&w);
a--;
fx = find(a);
fy = find(b);
if (fx != fy)
{
fa[fy] = fx;
r[fy] = w + r[a] - r[b];
}
else if (r[b] - r[a] != w)
ans++;
}
printf("%d\n", ans);
}
return ;
}
有长度为n的01序列, 有m个限制条件
ai bi even/odd 表示从ai到bi, 1的个数为偶数/奇数
限制条件有可能相互矛盾, 题目要我们求出从哪里开始出现矛盾
和上面那题一条的, cnt[bi] - cnt[ai-1] 表示从ai到bi的1的个数
然后ai-1作为父亲, bi作为儿子, 如果两者相减是偶数, 那么权值为0,如果是奇数, 权值为1.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = << ;
/* */
std::map<int, int> ma;
const int N = + ;
int fa[N], rank[N];
int find(int x)
{
if (x == fa[x])
return x;
int f = fa[x];
fa[x] = find(fa[x]);
rank[x] = (rank[x] + rank[f]) % ;
return fa[x];
}
int main()
{
int n, m;
int a, b, fx, fy, d;
char str[];
scanf("%d%d", &n, &m);
for (int i = ; i < N; ++i)
{
fa[i] = i;
rank[i] = ;
}
int cnt = ;
int i;
for (i = ; i < m; ++i)
{
scanf("%d%d%s", &a, &b, str);
a--;
if (ma[a] == )
ma[a] = ++cnt;
a = ma[a];
if (ma[b] == )
ma[b] = ++cnt;
b = ma[b];
if (str[] == 'o')
d = ;
else
d = ;
fx = find(a);
fy = find(b);
if (fx != fy)
{
fa[fx] = fy;
rank[fx] = (rank[a] + rank[b] + d) % ;
}
else if ((rank[a] + rank[b]) % != d)
break;
}
printf("%d\n", i);
return ;
}
n个点, m行条件, 每行 F1 F2 L E/W/N/S 表示F2在F1的E/W/N/S方向, 且距离为L
然后有q个询问,每个询问F1 F2 i 表示在已知前i个条件的情况下,求F1和F2的笛卡尔距离。如果无法得到输出-1
分析:其实也是维护元素与元素之间的关系, 只不过关系是他们的笛卡尔距离, 同样的, 这种关系同样具有传递性
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/*
这次用并查集来维护的依旧是元素与元素之间的关系, 只不过关系是笛卡尔距离
*/
const int N = + ;
int fa[N], rx[N], ry[N];
int F1[N], F2[N], L[N], D[N];
int find(int x)
{
if (x == fa[x]) return x;
int f = fa[x];
fa[x] = find(fa[x]);
rx[x] = (rx[x] + rx[f]);
ry[x] = (ry[x] + ry[f]);
return fa[x];
} int main()
{
int n, m, q;
char str[];
int x, y, k, fx, fy;
int i;
while (scanf("%d%d", &n, &m) != EOF)
{
for ( i = ; i <= n; ++i)
{
fa[i] = i;
rx[i] = ry[i] = ;
}
for ( i = ; i <= m; ++i)
{
//E 用0表示
scanf("%d%d%d%s", &F1[i], &F2[i], &L[i], str);
if (str[] == 'W')
{
swap(F1[i], F2[i]);
D[i] = ;
}
else if (str[] == 'E')
D[i] = ;
else if (str[] == 'N')
{
swap(F1[i], F2[i]);
D[i] = ;
}
else
D[i] = ;
}
scanf("%d", &q);
i = ;
while (q--)
{
scanf("%d%d%d", &x, &y, &k);
for (; i <= k; ++i)
{
fx = find(F1[i]);
fy = find(F2[i]);
if (fx != fy)
{
fa[fy] = fx;
if (D[i] == )
{
//L[i] - rx[F2[i]] 得到fy与F1[i]的相对距离
//再加上F1[i]与fx的相对距离,得到了 fy与fx的相对距离
rx[fy] = rx[F1[i]] + L[i] - rx[F2[i]];
ry[fy] = ry[F1[i]] + - ry[F2[i]];
}
else
{
rx[fy] = rx[F1[i]] + - rx[F2[i]];
ry[fy] = ry[F1[i]] + L[i] - ry[F2[i]];
}
}
}
fx = find(x);
fy = find(y);
if (fx != fy)
puts("-1");
else
{
int ans = abs((rx[y] - rx[fy]) - (rx[x] - rx[fx])) + abs((ry[y] - ry[fy]) - (ry[x] - ry[fx]));
printf("%d\n", ans);
}
} }
return ;
}
逆向并查集,离线存储后,逆向过来建并查集
给定n个星球, 每个星球有能量值pi,
给定m条边, 表示
然后有两种操作 query a 找到与a连通的能力最大的星球(这个星球的能力要比a大),如果有多个最大的,那么输出编号最小的
destory a b 摧毁a和b之间的道路
并查集要删边很困难,但是我们可以逆向来建并查集。且维护一个集合的父亲为这个集合中权值最大的元素,如果权值相同则设编号小的为父亲
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
#include <unordered_map>
#include <unordered_map>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/*
给定n个星球, 每个星球有能量值pi,
给定m条边, 表示
然后有两种操作 query a 找到与a连通的能力最大的星球(这个星球的能力要比a大),如果有多个最大的,那么输出编号最小的 找到连通的???
set<pair<int,int> >; lower_bound(
*/
const int N = + ;
int val[N];
int fa[N];
int u[N * ], v[N * ];
int a[N * ], b[N * ], ans[N * ];
unordered_map<int, int> ma[N];//要开一个数组,
int find(int x)
{
if (fa[x] == x)
return x;
return fa[x] = find(fa[x]);
}
void unionSet(int x, int y)
{
int fx = find(x);
int fy = find(y);
if (fx != fy)
{
if (val[fx] > val[fy])
fa[fy] = fx;
else if (val[fx] < val[fy])
fa[fx] = fy;
else
{
if (fx < fy)
fa[fy] = fx;
else
fa[fx] = fy;
}
}
}
void input(int &x)
{
char ch = getchar();
while (ch<'' || ch>'')
ch = getchar();
x = ;
while (ch >= '' &&ch <= '')
{
x = x * + ch - '';
ch = getchar();
}
}
int main()
{
int n, q, m;
char query[];
int t = ;
while (scanf("%d", &n) != EOF)
{
if (t != )
puts("");
t++; for (int i = ; i < n; ++i)
{
ma[i].clear();
input(val[i]);
fa[i] = i;
}
input(m);
for (int i = ; i < m; ++i)
{
//scanf("%d%d", &u[i], &v[i]);
input(u[i]);
input(v[i]);
if (u[i] > v[i])
swap(u[i], v[i]);
}
input(q);
for (int i = ; i < q; ++i)
{
scanf("%s", query);
if (query[] == 'q')
{
a[i] = -;
input(b[i]);
}
else
{
input(a[i]);
input(b[i]);
if (a[i] > b[i])
swap(a[i], b[i]);
ma[a[i]][b[i]] = ;
}
}
for (int i = ; i < m; ++i)
{
if (ma[u[i]][v[i]]!=)
unionSet(u[i], v[i]);
}
for (int i = q - ; i >= ; --i)
{
if (a[i] == -)
{
int fx = find(b[i]);
if (val[fx] > val[b[i]])
ans[i] = fx;
else
ans[i] = -;
}
else
{
ans[i] = -;
unionSet(a[i], b[i]);
}
}
for (int i = ; i < q; ++i)
if (ans[i] != -)
printf("%d\n", ans[i]);
}
return ;
}
并查集专辑 (poj1182食物链,hdu3038, poj1733, poj1984, zoj3261)的更多相关文章
- 【带权并查集】poj1182 食物链
带权并查集,或者叫做种类并查集,经典题. http://blog.csdn.net/shuangde800/article/details/7974668 这份代码感觉是坠吼的. 我的代码是暴力分类讨 ...
- [并查集] POJ 1182 食物链
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 66294 Accepted: 19539 Description ...
- 并查集(POJ1182)
链接:http://poj.org/problem?id=1182 定义一种关系R(x,y),x > y 时 R(x,y) = 2:x = y 时 R(x,y)= 1:x < y 时 R( ...
- (并查集 建立关系)食物链 -- POJ-- 1182
链接: http://poj.org/problem?id=1182 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82830#probl ...
- 【并查集】PKU-1182 食物链
食物链 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不 ...
- The Suspects (并查集)
个人心得:最基础的并查集经典题.借此去了解了一下加深版的即加权并查集,比如食物链的题目,这种题目实行起来还是有 一定的难度,不仅要找出与父节点的关系,还要在路径压缩的时候进行更新,这一点现在还是没那么 ...
- NOI2001|POJ1182食物链[种类并查集 向量]
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 65430 Accepted: 19283 Description ...
- 种类并查集——带权并查集——POJ1182;HDU3038
POJ1182 HDU3038 这两个题比较像(一类题目),属于带权(种类)并查集 poj1182描绘得三种动物种类的关系,按照他一开始给你的关系,优化你的种类关系网络,最后看看再优化的过程中有几处矛 ...
- POJ1182 食物链---(经典种类并查集)
题目链接:http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submission ...
随机推荐
- ios添加pre和post build action
再vs中,我们可以很方便的再build前.后执行一些脚本为我们做点什么事情.再ios中怎么搞呢,哪必然是对xcode进行操作了.再google搜索了一把,有说操作Scheme的也有说再直接再targe ...
- alv行可编辑时带出描述
ALV显示可以编辑的状态下可以带出描述信息等,比如维护表程序输入公司代码时需要带出公司代码的描述,这时就需要通过下面事件来触发 定义一个类: CLASS lcl_event_receiver DEFI ...
- 手动配置S2SH三大框架报错(三)
十二月 08, 2013 10:24:43 下午 org.apache.catalina.core.AprLifecycleListener init 严重: An incompatible vers ...
- MFC消息响应机制分析
---- 摘要: ---- MFC是Windows下程序设计的最流行的一个类库,但是该类库比较庞杂,尤其是它的消息映射机制,更是涉及到很多低层的东西,我们在这里,对它的整个消息映射机制进行了系统的分析 ...
- golang使用pprof检查goroutine泄露
有一段时间,我们的推送服务socket占用非常不正常,我们自己统计的同一时候在线就10w的用户,可是占用的socket居然达到30w,然后查看goroutine的数量,发现已经60w+. 每一个用户占 ...
- Swift - 页控件(UIPageControl)的用法
使用页控件可以用来展示多个桌面.比如很多应用第一次登陆时,会在开始页面使用页控件来介绍功能,通过左右滑动来切换页. 通常我们使用UIPageControl和UIScrollView相互结合来实现多页切 ...
- JSP内置对象Session
创建和获取客户的会话 setAttribute()与getAttribute() session.setAttribute(String name , Object obj) 如session.set ...
- 初窥Linux 之 区分硬连接和软连接
一.Linux下的两种连接文件及创建方式 在Linux下面的连接文件有两种——软连接和硬连接,虽然都是连接文件,但两者却有很大的区别.一种是类似于Windows的快捷方式功能的文件(或目录),这种连接 ...
- 终于懂了:TControl.Perform是有返回值的,且看VCL框架如何利用消息的返回值(全部例子都在这里)——它的存在仅仅是为了方便复用消息的返回值
代码如下: function TControl.Perform(Msg: Cardinal; WParam, LParam: Longint): Longint; var Message: TMess ...
- STL的一些泛型算法
源地址:http://blog.csdn.net/byijie/article/details/8142859 从福州大学资料里摘下来的我现在能理解的泛型算法 algorithm min(a,b) 返 ...