终于做到有我们学校出的多校题了,感动。。。
但是这道并查集并不是那么简单额,想了我好久,现在还是提留有一点点感性的认识,也不知道自己想的对不对。
推荐博客:http://www.cnblogs.com/wally/archive/2013/06/10/3130527.html(但是它好像有一点写的太简略了,应该是当两个人座位间的差值不等于要求的差值的话,那么才是不符合要求的)
题意:
有一个体育场,是圆形的,它的列数标号从1到300,它的行数是无限大的,而且这个体育场是顺时针的。然后现在有n个人要来观看比赛,输入为:“a b x”,然后他们要满足的要求是b必须坐在离a顺时针x距离的地方。
问你有多少是不满足条件的。
思路:
想到是并查集了,但是感觉这道题好复杂并不怎么会做。。。
当两个人到根节点的差值不等于他们之间的距离x时,那么就算是冲突了。
搜了好多题解,感觉都是千篇一律,后来看了代码理解感性理解了一下,但是对向量那个地方还不是很懂。。
个人觉得图应该是这样画的。
这幅图的大致意思是:这里我们始终以ra点作为祖先点,如果每次读入时a,b的祖先不相同的话,那么就把b连到a的祖先即为ra上去,别忘了还要更新b的根节点到ra的距离,这里我们也用了一个相当于是lazy思想,就是只改变rb到ra的距离,至于b到ra的距离,这里我们可以在find祖先时,通过路径压缩来改变。
那么距离根据向量法则可得为:dis[rb]=dis[b]-dis[a]+x;
那么怎样判断是不符合条件的说法呢,当dis[rb]-dis[ra]!=x时,那么就是不符合条件的说法了。
但是这里我始终不是很明白的就是他们两个人坐的行数有没有关系呢,还有这是一个圆弧形的,为什么可以用直线型的向量来表示呢?
#include<stdio.h>
#include<string.h>
#define maxn 55555
int par[maxn],dis[maxn];
int count=0;
//想法:如果它们两个人到根节点的距离!=x的话,那么就发生冲突了
void init(){
for(int i=0;i<=maxn;i++){
par[i]=i;
dis[i]=0; //dis数组保存的是它们到根节点的距离
}
}
int find(int x){
if(x==par[x]) return x;
int temp=par[x];
par[x]=find(par[x]);
dis[x]+=dis[temp]; //这里相当于是路径压缩,不断求出它们到根节点的距离
return par[x];
}
void merge(int x,int y,int s){
int tx,ty;
tx=find(x);
ty=find(y);
if(tx!=ty){
par[ty]=tx;
dis[ty]=dis[x]+s-dis[y];
}
else{
if(dis[y]-dis[x]!=s) count++;
}
}
int main(){
int n,m;
int a,b,x;
while(~scanf("%d%d",&n,&m)){
init();
count=0;
while(m--){
scanf("%d%d%d",&a,&b,&x);
merge(a,b,x);
}
printf("%d\n",count);
}
}