食物链
节点的 re[ ] 值记录与父节点的关系:
0:同类
1:吃父结点
2: 被父结点吃
今天上英语课又想了一下,应该是想明白了。
为什么1是指被父节点吃2是指吃父结点,也不是随便定的。而是根据题意:
当m = 1时, x 与 y 的关系为同类,根据规定的关系值就为 m - 1 = 0;
当m = 2时, x 与 y的关系为 x 吃 y ,根据规定的关系值就为 m - 2 = 1;
const int maxn=5*1e4;
int fa[maxn+5]; //代表父结点
int re[maxn+5]; //代表该点与父结点的关系
void init(int n)
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
re[i]=0;
}
}
int get(int x)
{
if(fa[x]==x)return x;
int t=fa[x];
fa[x]=get(t);
re[x]=(re[x]+re[t])%3;
return fa[x];
}
void Merge(int x,int y,int m)
{
int gx=get(x);
int gy=get(y);
fa[gy]=gx; //统一将x的父节点设为y的父亲节点
re[gy]=(re[x]+(3-re[y])+(m-1))%3;//找到x、y之间的关系
//fa[x]与x的关系为(3-re[x])%3
//x和y的关系就是(re[x]+re[y])%3;
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
init(n);
int m,x,y;
int cnt=0;
while(k--)
{
scanf("%d%d%d",&m,&x,&y);
if((m==2&&x==y)||x>n||y>n)
{
cnt++;
continue;
}
if(get(x)!=get(y)) //两者还没有建立关系
{
Merge(x,y,m);
}
else
{
if(m==1&&re[x]!=re[y])cnt++; //m=1与父结点的关系应相同
if(m==2&&(re[x]+1)%3!=re[y])cnt++; //m=2 x对父为1,则y对父应为2
} // y对父为2,则x对父应为0
}
cout<<cnt<<endl;
return 0;
}
银河英雄传说
带权并查集
开一个数组表示结点的权值,权值表示到父亲节点的距离。
一开始一直全wa,在小ao的帮助下才发现把 c 的类型由 char 改为 string 就可以过了,为什么我是不知道为什么的.
const int maxn=3*1e5;
int fa[maxn+5];
int dis[maxn+5];//到根节点的距离
int num[maxn+5];//该根节点所在集合的元素个数
void init()
{
for(int i=1;i<=30005;i++)
{
fa[i]=i;
dis[i]=0;
num[i]=1;
}
}
int get(int x)
{
if(fa[x]==x)return x;
int fx=fa[x];
fa[x]=get(fx);
dis[x]+=dis[fx];
num[x]=num[fx];
return fa[x];
}
int main()
{
init();
int t;scanf("%d",&t);
while(t--)
{
int x,y;string c;cin>>c;
scanf("%d%d",&x,&y);
if(c[0]=='M')
{
int gx=get(x);
int gy=get(y);
fa[gx]=gy;
dis[gx]+=num[gy];
num[gx]+=num[gy];
num[gy]=num[gx];
}
if(c[0]=='C')
{
int gx=get(x);
int gy=get(y);
if(gx!=gy)
{
printf("-1\n");
}
if(gx==gy)
{
printf("%d\n",abs(dis[x]-dis[y])-1);
}
}
}
return 0;
}