神奇&坑的一题。中文题题意不解释,注意这里输入只有一组数据,EOF会报WA。详解请参考http://blog.csdn.net/c0de4fun/article/details/7318642
这里看两点:1,处理路径压缩时候的关系。2,集合合并时候的关系,当然1 是 2 的前提
1.首先定义节点之间的关系(这里的关系就是a == b, a 吃 b, b 吃 a ,a 是 b 父亲),那么定义x = a - b; 有前面得x = 0表示a,b同属一物种,x = 1表示a 吃 b ,x = 2表示 b 吃 a
那么显然可以得到下面两点:
- ani [ now ].parent = ani [ ani [ now ].parent ].parent; //即当前儿子的祖先节点是其父亲的祖先节点
- ani [ now ] .relation = ( ani [ now ] .relation + ani [ now.parent ] .relation ) % 3; //通过枚举儿子,父亲,及父亲的祖先节点的关系(这里的关系就是a == b, a 吃 b, b 吃 a)
2.在集合合并的时候,如下图,当前的两个节点是x, y,那么合并x,y所在集合,在普通并查集里面就是将y的祖先节点,也就是b,指向x的祖先节点,也就是a(a, b都由1的路径压缩得到),但是我们怎么确定a 和 b 的吃与被吃间的关系呢?
由已经得到答案的问题1可以知道,当知道儿子与父亲关系,父亲与父亲的祖先关系,可以推得儿子与父亲的祖先的关系。而在这里,我们已经知道b是y 路径压缩过的祖先,直接当成父亲看也可以,根据b 与 y之间的关系(假设b 吃 y),那么逆推下,即看成 y 是 b的儿子,则b 与 y的关系 x 就变成 x = ( 3 - x ) % 3,那么就如下图一样,我们可以先有b(儿子)->y(父亲)>x(爷爷)的关系将b连在x上,再由b > x -> a的关系确定b 与 a的关系。 以上,将y 的祖先 b 的父亲指向x 的祖先 a,并确定b 与 a的关系,就成功的合并x, y两个点所在的集合了
再谈想法正确性:假设x, y所属的不相关两个集合里面的关系都是自洽的,那么合并两个集合之后得到的新集合是否还是自洽的?
我们假设 x 集合里面有个点z,与x所在集合是满足关系的,而与y所属集合里面有些点矛盾,例如w,那么由z, w之前就应该合并为同一个集合,而z, w,分别从属两个不相关的集合,显然矛盾,所以假设不成立
最后如何计算假话的数量? 我们只能从已知条件推得当前说的话是否成立,当前条件就是询问的两个点从属同一个集合,不从属的话直接合并两个点就行了。对于两种关系d = 1, d = 2,通过枚举得到,如果是同一个物种,则有x1 = x2,否则就是x1 = x2 + 1
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define pi acos(-1.0)
#define eps 1e-8
#define asd puts("sdasdasdasdasd");
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 50050;
struct node{
int fa, re, x;
//re for relation, 0 for same, 1 for father eat son, 2 for son eat father
}a[N];
int n, d, k;
void init()
{
for( int i = 1; i <= n; ++i )
{
a[i].x = i;
a[i].fa = i;
a[i].re = 0;
}
}
int dfs( node &t )
{
if( t.x == t.fa )
return t.x;
int fa = t.fa;
//printf("Animal %d s Parent is %d\n",t.x,t.fa);
t.fa = dfs( a[fa] );
t.re = ( t.re + a[fa].re ) % 3;
return t.fa;
}
void Union( int x, int y, int xx, int yy, int d )
{
a[yy].fa = xx;
a[yy].re = ( (3 - a[y].re) + (d - 1) + a[x].re ) % 3;
}
int main()
{
//while( ~scanf("%d%d", &n, &k) )
scanf("%d%d", &n, &k);
{
init();
int x, y, ans = 0;
while( k-- )
{
scanf("%d%d%d", &d, &x, &y);
if( x > n || y > n || ( d == 2 && x == y ) )
{
ans++;
continue;
}
int xx = dfs( a[x] );
int yy = dfs( a[y] );
if( xx != yy ) // not same set
{
Union( x, y, xx, yy, d );
continue;
}
if( d == 1 )
{
if( a[x].re != a[y].re )
ans++;
}
else
{
if( ( a[y].re + 3 - a[x].re ) % 3 != 1 )
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}