• POJ 1182 食物链(并查集+偏移向量)题解


    食物链
    Time Limit: 1000MS Memory Limit: 10000K
    Total Submissions: 82346 Accepted: 24616

    Description

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 
    现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 
    有人用两种说法对这N个动物所构成的食物链关系进行描述: 
    第一种说法是"1 X Y",表示X和Y是同类。 
    第二种说法是"2 X Y",表示X吃Y。 
    此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
    1) 当前的话与前面的某些真的话冲突,就是假话; 
    2) 当前的话中X或Y比N大,就是假话; 
    3) 当前的话表示X吃X,就是假话。 
    你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 

    Input

    第一行是两个整数N和K,以一个空格分隔。 
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
    若D=1,则表示X和Y是同类。 
    若D=2,则表示X吃Y。

    Output

    只有一个整数,表示假话的数目。

    Sample Input

    100 7
    1 101 1 
    2 1 2
    2 2 3 
    2 3 3 
    1 1 3 
    2 3 1 
    1 5 5
    

    Sample Output

    3
    思路:

    因为要表达并查集间的关系,所以我们设了一组数组rela[i]来表示i与他的根之间的关系(即表示i到pre[i]的偏移量),假设a b,0表示同类,1表示a吃b,2表示b吃a。


    在压缩路径时,我们需要对沿途的数据更新rela:rela[a]=(rela[a]+rela[ pre[a] ])%3;  此代码应这样理解:rela表示的是a对当前的根aa的偏移量,即a->aa,而aa对最顶端的根fa偏移量为rela[ aa ],即aa->fa,所以将两者相加(注意!这是个向量,即a->根)就为a对最顶端的根fa偏移量,即a->fa。


    在执行join时我们注意到我们需要更新合并后fb的rela,代码为:rela[fb]=(3-rela[b]+(c-1)+rela[a])%3;  要了解这个,首先我们要知道一个知识:

    假如x作为y的根时,y的偏移量是a(即y->x),那么y作为x的父亲时,x的偏移量就是(3 - a)%3(即x->y)

    所以代码应这样理解:(3-rela[b])是fbb的偏移量即fb->b, (c-1)是ba偏移量即b->a,(rela[a]) 是a对fa的原根偏移量

    即a->fa ,所以fb->b +b->a + a->fa =fb->fa,即为fb对fa偏移量。


    我也是在看了大佬详细解说之后才恍然大悟,特奉上参考博客:点此

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<stdlib.h>
    #include<map>
    #define N 50010
    #define HASH 10000
    using namespace std;
    int pre[N],rela[N],c;
    
    int find(int a){
    	if(pre[a]==a)	return a;
    	else{
    		int temp=pre[a];
    		pre[a]=find(temp);
    		rela[a]=(rela[a]+rela[temp])%3;	//当前a对根的偏移量 
    		return pre[a];
    	}
    }
    void join(int a,int b){
    	int fa=find(a);
    	int fb=find(b);
    	if(fa!=fb){
    		pre[fb]=fa;
    		rela[fb]=(3-rela[b]+(c-1)+rela[a])%3;//(3-rela[b])是b与原根fb的偏移量, (c-1)是a b间偏移量,(rela[a]) 是a和它的原根fa偏移量 ,三者相加为fa fb间偏移量
    	}
    }
    int main(){
    	int n,i,k,answer=0,a,b;
    	scanf("%d%d",&n,&k);
    	for(i=0;i<=n;i++){
    		pre[i]=i;
    		rela[i]=0;
    	}
    	while(k--){
    		scanf("%d%d%d",&c,&a,&b);
    		if(c==2 && a==b)	answer++;
    		else if(a>n ||b>n)	answer++;
    		else if(find(a)!=find(b)){
    			join(a,b);
    		}
    		else if(c==1){
    			if(rela[a]!=rela[b])
    				answer++;
    		}
    		else{
    			if( ((rela[b]+3-rela[a])%3)!=1 )	//代表a为b根时b的偏移量 
    				answer++;
    		}
    	}
    	printf("%d
    ",answer);
    	return 0;
    } 

  • 相关阅读:
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1105:数组逆序重存放
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1106:年龄与疾病
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1105:数组逆序重存放
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1104:计算书费
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1104:计算书费
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1104:计算书费
    configparser
    python中split()、os.path.split()函数用法
    DOS命令
    adb安装及使用
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9409140.html
Copyright © 2020-2023  润新知