加权并查集是一种特殊的并查集,除可提供查询操作外,还可用于表示元素与其代表元素的关系。下面以食物链为例,讲解一下加权并查集。
#include<cstdio> //调用cstdio库,使用getchar函数 #include<cctype> //调用cctype库,使用isdigit函数,返回参数是否为整数 int N,K,ans,r,x,y; //定义变量用于有几个动物,几句话,答案,以及动物的关系和两个要描述的动物 int f[50005],d[50005]; //定义数组记录代表元素,以及到达代表元素的距离 inline int get_num() { //内联get_num函数,读入整数 int num = 0; //定义整型变量num,并赋值为0 char c; //定义字符型变量c bool flag = false; //定义布尔值变量flag,并置为假 while ((c = getchar()) == ‘ ‘ || c == ‘\n‘ || c == ‘\r‘); //忽略开头的空格,换行符及回车符 if (c == ‘-‘) flag = true; //如果读到负号,就将负数标志置为真 else num = c - ‘0‘; //否则将读到的第一个数字保存; while (isdigit(c = getchar())) //只要读入的还是数字,就循环 num = num * 10 + c - ‘0‘; //将num整体前移一位,并将新读入的一位数字保存 return (flag ? -1 : 1) * num; //返回读到的整数,若负数标志为真,就返回其相反数,即一个负数 } int find(int i) { //定义函数查询代表元素以及到达代表元素的距离 if(i==f[i]) return i; //找到代表元素返回 int oldf=f[i]; //记录下元素之前的代表元素 f[i]=find(f[i]); //更新元素的代表元素 d[i]=(d[i]+d[oldf])%3; //更新元素与代表元素的距离 return f[i]; //返回代表元素 } void check(int r,int x,int y) { //定义函数检查是否为假话 if(x>N||y>N) {++ans;return;} //若动物编号超出范围,则为假话 if(r==2&&x==y) {++ans;return;} //若说动物自己吃自己,则为假话 if(find(x)==find(y)) { //若两个动物在同一集合中 if((d[x]-d[y]+3)%3!=r-1) ++ans;return; //动物之间的距离不符合描述,则为假话 } else { d[f[x]]=(3-d[x])%3; //求出代表元素到该元素的距离 f[f[x]]=x;f[x]=y; //让代表元素指向该元素,即该元素成为代表元素,并指向y d[f[y]]=(3-d[y])%3; //同上 f[f[y]]=y;f[y]=y;d[y]=0; // 同上,并让y成为代表元素,令其到代表元素的距离为0 if(r==1) d[x]=0; //若为同类,则x到y距离为0 else d[x]=1; //若x吃y,则x到y距离为1 /* 另一种合并方法 f[f[y]]=f[x]; //让y的代表元素指向x的代表元素 d[f[y]]=(d[x]-d[y]-(r-1)+3)%3; //更新y的代表元素到其代表元素的距离 */ } } int main() { N=read();K=read(); //读入N,K for(int t=1;t<=N;++t) f[t]=t; //初始化每个元素的代表元素 for(int t=1;t<=K;++t) { //遍历每句话 r=read();x=read();y=read(); //读入r,x,y check(r,x,y); //调用check函数 } printf("%d",ans); //打印答案 return 0; }
时间: 2024-10-14 06:33:35