题意:
中文题。。。不用我说了吧
题解:
这道题不管是我几个月前做还是现在做都不会做。。但是自从看了一个dalao的博客之后,我感觉我的任督二脉都打通了,突然感觉带权并查集没有以前看到的那么可怕。ORZ,膜拜dalao。我发一下链接:http://blog.csdn.net/niushuai666/article/details/6981689
我非常推荐你认真地观看,看了之后你会发现,这道题没有想象中的那么难,反而可以通过这道题达到举一反三的效果。dalao用向量的思想去做这道题的思路让我醍醐灌顶,大为感叹,当初为什么没有早点遇到这么好的博客,其中数学强真的是可以为所欲为啊ORZ。
但是有一点要指出的是:(我也不知道是不是对的,但是我认为dalao这里可能口误了)
由上面可知:
x->y 偏移量0时 x和y同类
x->y 偏移量1时 x被y吃
x->y 偏移量2时 x吃y
这里的正确的关系应该为
x->y 偏移量0时 x和y同类
x->y 偏移量1时 x吃y
x->y 偏移量2时 x被y吃
如果还不懂dalao的讲解的话,可以看一下我写的东西(虽然没啥作用)
这里还有一个操作就是find压缩路径操作中,一定要回溯到根节点(即找到祖宗)再更新关系,不然会出现错误,什么错误呢?如果你是从后面一路更新上去到祖宗那里的话,就会出现后面影响前面,而与题目要求的:当前的话与前面的某些真的话冲突,就是假话; 这个条件产生影响,导致出错。必须要回溯到根节点,再进行更新,就是为了防止出现后面的影响前面的一些正确观点。谨记!我就是在这里WA(死)了很多次。。。
我还是贴上我的垃圾代码吧
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXN=5e4+7;
struct node
{
int f,r;
}a[MAXN];
void init(int n)
{
for(int i=1;i<=n;i++)
a[i].f=i,a[i].r=0;
}
int find(int p)
{
while(p!=a[p].f)
{
int temp=a[p].f;
a[p].f=find(temp);
a[p].r=(a[p].r+a[temp].r)%3;
p=a[p].f;
}
return p;
}
int Union(int p,int q,int d)
{
int P=find(p);
int Q=find(q);
if(P==Q)
{
if(d-1!=(3-a[p].r+a[q].r)%3)
return 1;
}
else
{
a[Q].f=P;
a[Q].r=(d-1+a[p].r+3-a[q].r)%3;
}
return 0;
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
init(n);
int sum=0;
for(int i=1;i<=k;i++)
{
int d,u,v;
scanf("%d%d%d",&d,&u,&v);
if(u>n||v>n)
sum++;
else if(d==2&&u==v)
sum++;
else if(Union(u,v,d))
sum++;
}
printf("%d\n",sum);
return 0;
}