地址:http://acm.bit.edu.cn/mod/programming/view.php?a=549
经典拓展(真)并查集,多码几次没坏处。
难点:merge时,relation的变更容易搞混。原理是b对a的关系等于b对c+c对a的关系(注意有先后)。故merge时已知a对roota关系temp1.r,b对roota关系temp2.r,a对b关系s,则roota对rootb关系为 -temp1.r+s+temp2.r 然后+3再%3(防止负数取余)
WA点:注意不要出现负数取余。
#include<iostream>
#define N 50005
int parent[N],relation[N]; //2表示被吃,1表示吃,0表示同类
typedef struct NODE
{
int p,r;
}node;
node ans,temp1,temp2;
node root(int a)
{
if(parent[a]==-1)
{
ans.p=a,ans.r=0;
return ans;
}
ans=root(parent[a]);
ans.r=relation[a]=(ans.r+relation[a])%3; //路径压缩优化
parent[a]=ans.p;
return ans;
}
void merge(int s,int a,int b)
{
node roota=root(a),rootb=root(b);
parent[roota.p]=rootb.p;
relation[roota.p]=(rootb.r-roota.r+s+3)%3;
}
int main()
{
int n,k;
int cmd,t1,t2;
int res;
while(~scanf("%d%d",&n,&k))
{
memset(relation,0,sizeof(relation));
memset(parent,-1,sizeof(parent));
res=0;
while(k--)
{
scanf("%d%d%d",&cmd,&t1,&t2);
if(t1>n||t2>n||(t1==t2&&cmd==2))
{
res++;
continue;
}
temp1=root(t1),temp2=root(t2);
if(cmd==1)
{
if(temp1.p==temp2.p)
{
if(temp1.r==temp2.r) continue;
else
{
res++;
continue;
}
}
else merge(0,t1,t2);
}
else
{
if(temp1.p==temp2.p)
{
if((temp1.r-temp2.r+3)%3==1) continue;
else
{
res++;
continue;
}
}
else merge(1,t1,t2);
}
}
printf("%d\n",res);
}
return 0;
}
1062 Find them, Catch them
地址:http://acm.bit.edu.cn/mod/programming/view.php?a=548
弱化版。
#include<iostream>
using namespace std;
#define SIZE 100005
int parent[SIZE],relation[SIZE];
struct NODE
{
int p,r;
} temp1,temp2,ans;
struct NODE root(int n)
{
if(parent[n]==-1)
{
ans.p=n,ans.r=0;
return ans;
}
ans=root(parent[n]);
parent[n]=ans.p; //路径压缩
ans.r=relation[n]=(relation[n]+ans.r)%2;
return ans;
}
void merge(int a,int b)
{
temp1=root(a),temp2=root(b);
if(temp1.p==temp2.p) return;
parent[temp1.p]=temp2.p;
relation[temp1.p]=(temp1.r+temp2.r+1)%2;
}
int main()
{
int t,m,n,t1,t2;
char cmd;
scanf("%d",&t);
while(t--)
{
memset(parent,-1,sizeof(parent));
memset(relation,0,sizeof(relation));
scanf("%d%d%*c",&n,&m);
while(m--)
{
scanf("%c%d%d%*c",&cmd,&t1,&t2);
if(cmd=='D') merge(t1,t2);
else
{
temp1=root(t1),temp2=root(t2);
if(temp1.p!=temp2.p) printf("Not sure yet.\n");
else
{
if(temp1.r==temp2.r) printf("In the same gang.\n");
else printf("In different gangs.\n");
}
}
}
}
return 0;
}
1061 Ubiquitous Religions
地址:http://acm.bit.edu.cn/mod/programming/view.php?a=547
基础并查集。
#include<iostream>
using namespace std;
int father[50005];
bool flag[50005];
int m,n,t1,t2;
int root(int n)
{
if(father[n]<0) return n;
else return father[n]=root(father[n]);
}
void merge(int a,int b)
{
int roota=root(a),rootb=root(b);
if(father[roota]>father[rootb]) father[rootb]+=father[roota],father[roota]=rootb;
else father[roota]+=father[rootb],father[rootb]=roota;
}
int main()
{
int case0=1;
while(scanf("%d%d",&n,&m),m||n)
{
int ans=0;
memset(father,-1,sizeof(father));
memset(flag,0,sizeof(flag));
while(m--)
{
scanf("%d%d",&t1,&t2);
if(root(t1)!=root(t2)) merge(t1,t2);
}
for(int i=1;i<=n;i++)
{
if(!flag[root(i)]) ans++,flag[root(i)]=1;
}
printf("Case %d: %d\n",case0++,ans);
}
return 0;
}