poj1182-食物链-带权并查集-种类并查集*

(说实话这篇写的我自己都快看不懂,肯定会重写的!

 

题意和思路:

中文题意,我简单提一下:

A->B,B->C,C->A。A吃B,B吃C,C吃A,这是循环的。

r[] 数组保存的是 该节点和祖先节点的关系:

    0-和祖宗节点同类;

    1-吃祖宗节点;

     2-被祖宗节点吃。

输入c, a, b表示:

   if(c==1) a和b节点同类; 

   if(c==2) a吃b。

   注意:c-1就和最上面数字的数字表示相同的意思。

输出: 假语句的数量

 

题目链接:点击做题

AC代码:

把多组输入去掉就能AC,md,poj多组输入这个坑好烦啊啊啊啊!!!

#include<bits/stdc++.h>
#define mm1(a) memset((a),-1,sizeof((a)))  
#define mm0(a) memset((a),0,sizeof((a)))  
#define mmx(a) memset((a),0x3f,sizeof((a)))  
using namespace std;
typedef long long LL;
const int N = 50005;
const int INF = 1e9;
const int mod = 1e9 + 7;
#define DEBUG
int n,m;
int fa[N];
int r[N];
int Fi(int x){
	if(x!=fa[x]){
		int t=fa[x];
		fa[x]=Fi(fa[x]);
		r[x]=(r[x]+r[t])%3;
	}
	return fa[x];
}
void un(int a,int b,int c){
	int pa=Fi(a),pb=Fi(b);
	fa[pb]=pa;
	r[pb]=(r[a]+c-1-r[b]+3)%3;
	Fi(a),Fi(b);
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		mm0(r);
		for(int i=0;i<=n;++i)fa[i]=i;
		int ans=0,a,b,c;
		for(int h=0;h<m;++h){
			scanf("%d%d%d",&c,&a,&b);
			if(a>n||b>n||(c==2&&a==b)){
				ans++;continue;
			}
			int pa=Fi(a),pb=Fi(b);
			if(pa!=pb){
				un(a,b,c);
			}else{
				if(r[b]!=(r[a]+c-1)%3)ans++;
			}
		}
		printf("%d\n",ans );
	}
	return 0;
}

并查集的写法:

//int Fi(int x){
//    return fa[x]==x?x:fa[x]=Fi(fa[x]);
//}
inline int Fi(int x){
    int t=x,p;
    while(x!=fa[x])x=fa[x];
    while(t!=x)p=fa[t],fa[t]=x,t=p;
    return x;
}
int find1(int x){
    return x==fa[x]?x:fa[x]=find1(fa[x]);
}
inline int find2(int x){
    return x==fa[x]?x:fa[x]=find2(fa[x]);
}
inline int find3(int x){
    while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;
}
inline int find4(int x){
    int se=0;st[0]=x;
    while(fa[x]!=x)st[++se]=x=fa[x];
    while(se)fa[st[--se]]=x;
    return x;
}
inline int find5(int x){
    int t=x,p;
    while(x!=fa[x])x=fa[x];
    while(t!=x)p=fa[t],fa[t]=x,t=p;
    return x;
}
int find6(int x){
    return 0>fa[x]?x:fa[x]=find6(fa[x]);
}
inline int find7(int x){
    return 0>fa[x]?x:fa[x]=find7(fa[x]);
}
inline int find8(int x){
    while(fa[x]>=0&&fa[fa[x]]>=0)x=fa[x]=fa[fa[x]];return fa[x]<0?x:fa[x];
}

更多请访问:https://mcfx.us/archives/176/

int find(int x){
    int g = x , h;
    while(p[x] != x)  x = p[x];
    while(p[g] != x){
        h = p[g];
        p[g] = x;
        g = h;
    }
    return x;
}

 

我喜欢的写法:

int Fi(int x){
    return fa[x]==x?x:fa[x]=Fi(fa[x]);
}
inline int Fi(int x){
    int t=x,p;
    while(x!=fa[x])x=fa[x];
    while(t!=x)p=fa[t],fa[t]=x,t=p;
    return x;
}

inline int find3(int x){
    while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;
}

inline int find7(int x){
    return 0>fa[x]?x:fa[x]=find7(fa[x]);
}
inline int find8(int x){
    while(fa[x]>=0&&fa[fa[x]]>=0)x=fa[x]=fa[fa[x]];return fa[x]<0?x:fa[x];
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值