POJ 1182

Posted on 2011-07-20 23:18  continue_n  阅读(545)  评论(0)    收藏  举报

并查集


p(x)为x所属树的根节点。kind(x)为x与该树根节点的关系。height(x)为树x的高度。

现在规定:
0:同类关系。
1:吃关系。
2:被吃关系。
我们用x--r-->y表示x和y之间的关系是r,比如x--1--y代表x吃y。现在,若已知x--r1-->y,y--r2-->z,如何求x--?-->z?,于是我们不难发现,x--(r1+r2)%3-->z。有了这个结论,我们就可以做题了。
我们初始化kind(1-N)=0,表示自己和自己为同类。P(1-N)=i,代表各个节点都是一棵树。当D X Y时,则应合并X的根节点和Y的根节点,同时修改各自的kind。那么问题来了,合并了之后,被合并的根节点的kind值如何变化呢?
现有x和y,d为x和y的关系,px和py分别是x和y的根节点,于是我们有x--kind[x]-->px,y--kind[y]-->py,显然我们可以得到px--(3-kind[x])-->x,py--(3-kind[y])-->y。假如合并后px为新的树的根节点,那么原先px树上的节点不需变化,py树则需改变了,因为kind值为该节点和树根的关系。这里只改变kind(py)即可,因为在进行find_set操作时可相应改变py树的所有节点的kind值。于是问题变成了py--?-->px。我们不难发现py--(3-kind[y])-->y--(3-d)-->x--kind[x]-->px,根据前面的结论,我们有py--(3-kind[y]+3-d+kind[x])%3-->px。我们求解了px和py的关系了。


#include <stdio.h>
int father[50001];
int kind[50001];
int height[50001];
int Find(int x)
{
 if(father[x] == x) return x;
 int t;
 t = father[x];
 father[x] = Find(father[x]);
 kind[x] = (kind[x] + kind[t]) % 3;
 return father[x];
}
void Union(int px,int py,int x,int y,int d)
{
 if( height[px] < height[py] )
 {
  father[px] = py;
  kind[px] = (3-kind[x]+d+kind[y]) % 3 ;
 }
 else
 {
  if( height[px] == height[py] )
   height[px]++;
  father[py] = px;
  kind[py] = ( 3 - kind[y] + 3 - d + kind[x]) % 3;
 }
}
int main()
{
 int i,sum,n,t,d,x,y,px,py;
 scanf("%d%d",&n,&t);
 for( i = 1 ; i <= n ; i++)
 {
  father[i] = i;
  kind[i] = height[i] = 0;
 }
 sum = 0 ;
 while(t--)
 {
  scanf("%d%d%d",&d,&x,&y);
  if( x > n || y > n ) {sum++;continue;}
  if( d==2 && x==y ) {sum++;continue;}
  px = Find(x);
  py = Find(y);
  if( px == py )
  {
   if( d==1 && kind[x] != kind[y] ) {sum++;continue;}
   if(d==2&&(kind[x]+3-kind[y])%3!=1)
   //else if( d==2 && !(kind[x]==1&&kind[y]==0) && !(kind[x]==0&&kind[y]==2) && !(kind[x]==2&&kind[y]==1) )
    {sum++;continue;}
  }
  else
   Union(px,py,x,y,d-1);
 }
 printf("%d\n",sum);
 return 0;
}

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3