题目大意:大家都懂。
思路:
今天给实验室的学弟学妹们讲的带权并查集,本来不想细讲的,但是被学弟学妹们的态度感动了,所以写了一下这个博客,思想在今天白天已经讲过了,所以直接上代码。
首先,带权并查集必备知识是向量加减规则,不熟悉的可以看我的另外一篇博客(点我)
先放图,模拟的是 x吃y 和x和y同类的向量合并。
这应该是最难的地方,很多东西白天已经讲过了,具体看代码,我写了比较详细的注释。
#include<iostream> #include<cstdio> using namespace std; const int maxn=50010; int p=300000; //p%3==0 由于下面有向量相减 可能部分value是负的,所以加上一个比较大的数字变成正数 int fa[maxn],n,k,ans,type,x,y,value[maxn]; //value数组 永远记录的都是 当前节点 到fa[x]的权值 此时fa[x]对应的value不一定更新了 ,需要find进行路径合并 //记住 find的功能是找爸爸 + 路径合并 + 更新value[x] // baba函数的功能是 联合 向量规则更新value // x->y的权值是1,就是x吃y int find(int x) { if(x==fa[x])return fa[x]; int tep=fa[x]; //先保存当前的还没有路径合并的父节点 fa[x]=find(fa[x]); //把 父节点权值信息更新 value[x]+=value[tep]; //value存的是x到之前的父节点的信息,现在加上 原父节点(tep)合并路径后的权值 return fa[x]; } void baba(int x,int y,int type) { int fx=find(x),fy=find(y); if(type==1) //平级权值为0 { fa[fx]=fy; value[fx]=-value[x]+value[y]+0; //x的爸爸认y的爸爸当爸爸,用向量规则进行加减 }else{ //x吃y 权值1 fa[fx]=fy; value[fx]=-value[x]+value[y]+1; //x的爸爸认y的爸爸当爸爸,用向量规则进行加减 } } int main(){ cin>>n>>k; for(int i=1;i<=n;i++) { fa[i]=i; } while(k--) { scanf("%d%d%d",&type,&x,&y); if(x>n||y>n||(x==y&&type==2)){ //如果标号大于n 或者自己吃自己 肯定错 ans++; continue; } if(find(x)!=find(y)) //如果父亲不同 不在同一集合 肯定不会错 现在合并(因为现在给出的信息已经是限制条件了) { baba(x,y,type); //合并的类型是type }else{ if(type==1) //如果是平级的 { if((value[x]+p)%3!=(value[y]+p)%3){ //距离根节点的权值 取余3相等才合法(也就是和根节点的相食关系一致) ans++; //不合法 加加 } }else{ if((value[x]-value[y]+p)%3==1||(value[y]-value[x]+p)%3==2){ //合法就是x吃y,所以要么x比y大1,要么y比x大2(石头剪子布) }else{ ans++; } } } } cout<<ans<<endl; }