poj 1182 食物链 && nyoj 207(带权并查集)

食物链

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 52414   Accepted: 15346

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

题意为:有A、B、C三种动物,A吃B,B吃C,C吃A,并给出一些条件,判断为你提供信息的人说了多少句假话。

并查集,通常用来检查两个元素是否在同一集合中,或者是将两个不同的集合为一个集合。

至于这道题,有神人曰,利用并查集,同时对每个节点保持其到根结点的相对类别偏移量,定义为:

0——同类;

1——食物;

2——天敌。

所以我们还要知道相对类别偏移量怎么求。

对于输入的关系 d x y :

1). 如果 x, y 属于同一集合,判断两都关系是否合理:

x, y 为同一集合, 所以 x, y 指向同一根。 x 与根 rt 的关系距离为 dist[x],  y 与根 rt 的关系距离为 dist[y],根据输入 x 与 y 的关系距离为 d。有 d+ dist[y]== dist[x]  ( mod 3 )。

2). 如果 x, y 不属于同一集合有:

x 与 rx 属同一集合,rx 为 x 的根, y 与 ry 原同一集合,ry 为 y 的根。

rx!= ry, x 与 y 不属于同一集合,这时应当将 x, y 合并,这里合并时将 rx 指向ry,

ry 成了新集合的根:则有

d+ dist[y]== dist[x]+ dist[rx]  -->  dist[rx]= d+ dist[y]- dist[x]  求出了关系距离。

还有一个问题: x 与 y 合并后, ry 成了新集合的根,这时原来以 rx 为根的集合中的结点与 ry 的关系距离需要重新确定,如何确定:

假 设并查集树为 x->a->b->rx ->ry,  rx->ry 的关系距离已经求出,即 dist[rx] 已知, b 到 ry 的关系距离为 b 到 rx 的距离加上 rx 到 ry 的距离和。

故 dist[b]= dist[b]+ dist[rx]。 依次求出。

也就是 :对于一组数据 d x y,若x与y的根节点相同,

利用(dist[x]-dist[y]+3)%3!=d-1若不相等说明为假话;

若x与y根节点不同,说明两者不在同一集合里,进行组合。

让y的根fy成为x的根fx的父节点(father[fx]=fy),dist[fx]的值需要仔细归纳得出。

2015,7,27

这个输入用scanf()就过了。而cin却TLE了.

一个很详细的解题报告,看得我五体投地:http://blog.csdn.net/c0de4fun/article/details/7318642/

#include<stdio.h>
#define M 50005
int x[M],re[M];
void init()
{
	for(int i=0;i<M;i++){
		x[i]=i; re[i]=0;
	}
}
int find(int k)
{
	int temp=x[k];
	if(x[k]==k) return k;
	x[k]=find(x[k]);
	re[k]=(re[k]+re[temp])%3;//自己画个图就能验证,跟向量的加法类似,具体怎么推的我也不是太明白
	return x[k];
}
void merge(int a,int b,int fa,int fb,int d)
{
	x[fa]=fb;
	re[fa]=(re[b]-re[a]+d+3)%3;//这里是r[b]-r[a]
}
int main()
{
	int n,m,a,b,d,fa,fb,count=0;
	scanf("%d%d",&n,&m);
	init();
	while(m--){
		scanf("%d%d%d",&d,&a,&b);
		if( a>n || b>n || (a==b && d==2) ){
			count++;
			continue;
		}
		fa=find(a);
		fb=find(b);
		if(fa==fb&&(re[a]-re[b]+3)%3!=d-1)//这里是r[a]-r[b]与上边函数里边的不同 也可以画个图证明一下,具体为什么,原谅我还太菜
			count++;
		else
			merge(a,b,fa,fb,d-1);
	}
	printf("%d\n",count);
	return 0;
}
时间: 2024-10-24 23:35:44

poj 1182 食物链 && nyoj 207(带权并查集)的相关文章

POJ 1182 食物链(经典带权并查集 向量思维模式 很重要)

传送门: http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 90562   Accepted: 27216 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食

poj1182食物链,经典带权并查集

动物王国中有三类动物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句话有的是真的,有的是假的.当一句话满足下列三条之一时,这句话就是假话,否

poj 1962 Corporative Network(带权并查集)

题意: 在n个站点间建电线:两种操作: I a b表示以a为中心站点建线: E a表示查询以a站点为中心,相连的电线总长度: 思路: 带权并查集:中心站点就是父亲,电线长度为权值: #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int fa[500010],w[500010]; int t,n,m; char ch[5];

POJ 1988 Cube Stacking 【带权并查集】

<题目链接> 题目大意: 有几个stack,初始里面有一个cube.支持两种操作: 1.move x y: 将x所在的stack移动到y所在stack的顶部. 2.count x:数在x所在stack中,在x之下的cube的个数. 解题分析:由于要实现大量数的移动和归属关系,所以想到可能要用并查集,但是毫无疑问,普通的并查集不能够实现统计在x下的cube个数这一功能,所以我们通过带权并查集来实现,每一个stack,以最高的点为根,然后每一个点维护两个权值,它的子树节点个数(包括它自身),和它到

poj 1984 Navigation Nightmare(带权并查集+小小的技巧)

题目链接:http://poj.org/problem?id=1984 题意:题目是说给你n个线,并告知其方向,然后对于后面有一些询问,每个询问有一个时间点,要求你输出在该时间点a,b的笛卡尔距离,如果不存在则输出-1 其实就是将权值分一下x,y,x表示x轴方向的权值,y表示y轴方向的权值.然后最后询问时稍微有点技巧 可以先记录一下每次询问的位置然后再按照时间点从小到大来排序最后这样就方便并查集了. #include <iostream> #include <cstring> #i

poj 2912 Rochambeau(枚举+带权并查集)

题目链接:http://poj.org/problem?id=2912 题意:多个人玩石头剪刀布分成3组和一个裁判,每一组提前选定了自己出哪个手势,裁判可以随意出什么手势,问是否能够从给出的一系列石头剪刀布游戏中判断出哪个是裁判的,可以从第几局游戏中判断出来. 由于这题的数据量比较小可以枚举一下,枚举一下每一个人假设他们是裁判然后一系列并查集下来看 有没有出现矛盾如果没有那么这个人可能是裁判候补,如果有矛盾那么这个人肯定不是记录一下出现 问题的位置然后继续枚举.位置要去最远的,因为都要判完才知道

poj 1733 Parity game(带权并查集)

题目链接:http://poj.org/problem?id=1733 题意:给出一个01串然后给出一系列问题,问最多到哪位置问题出错了 这题和hdu3038类似思路也是差不多的 #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> using namespace std; struct TnT { int l

POJ 1988 Cube Stacking(带权并查集)

题意: 给定 n 个 方块, 然后有 p 个操作 操作M (a , b) , 就是将a方块所在的那一堆方块放到 b 上面. 操作C (x) , 就是询问x方块下面有多少方块 分析: 记录方块到父亲的距离dis, 还有最底的方块的cnt. 两个方块合并时,合并方块堆的父亲dis += 最底方块堆的cnt ,最底的方块堆的cnt 加上合并方块堆的 cnt 那么对于每个询问, 只要做一次路径压缩, 从根节点一直更新到询问点, 那么就能更新出询问点的长度 代码: 1 #include <bits/std

POJ 1988 Cube Stacking (带权并查集)

Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two typ