数据结构作业——山海经(带权并查集)
山海经
Description
有一天,阿翔去机房玩, 在 Dr_Ason 的桌子上发现了一本古代本子《 山海经》, 里面记载了这样一则故事——上古时期有 M 类犇(犇 1, 犇 2, …, 犇 M-1, 犇 M), 犇间形成了环状仰慕链:犇 1仰慕犇 2 ,犇 2仰慕犇 3 , … ,犇 M-1仰慕犇 M ,犇 M仰慕犇 1 。造物主犇顿由此发现了“犇势差” ——假设这个环上的 M 类犇是延顺时针编号为 1,2,…,M。对于犇 x和犇 y (x,y有序),犇 x与犇 y间的“ 犇势差” 为: 犇 x延顺时针到犇 y的距离。( 如 M 为 5 时, 犇 2与犇 2的犇势差为 0, 犇 2与犇 4的犇势差为 2, 犇 4与犇 2的犇势差为 3) 现在机房有 N 只牛, 以 1-N 编号。每一只牛都是远古的 M 类犇中某类犇的后 裔, 他们不仅继承了祖先的高配,还继承了祖先源远流长的 ym 套路: 犇 1 的后 裔仰慕犇 2 的后裔,犇 2 的后裔仰慕犇 3 的后裔,…,犇 M 的后裔仰慕犇 1 的后裔。 然而愚蠢的阿翔并不知道每只牛是哪类犇的后裔, 只好用另一种说法对这 N 只牛间的仰慕关系进行描述: “ d A B” , 表示编号为 A 的牛的祖先与编号为 B 的牛的祖先之间的犇势差 为 d( 0≤d≤M-1)。 阿翔用这种说法依次说出 K 句话,这 K 句话中有真有假。 如果一句话中的 A 或 B 比 N 大, 或者 d 大于等于 M, 或者这句话与之前的某句真话冲突, 它就是假 话,否则是真话。 请你输出这 K 句话中假话的数目。
Input
输入第一行为三个正整数 M, N, K,两数之间用一个空格隔开。
以下 K 行每行是三个整数 d, A, B, 两数之间用一个空格隔开。
30%数据: M=3, N=3, 1≤K≤10;90%数据: M=3, 1≤N≤50000, 1≤K≤100000; 100%数据: 3≤M≤30000, 1≤N≤50000, 1≤K≤100000。
Output
Sample Input
3 100 7
0 101 1
1 1 2
1 2 3
1 3 3
0 1 3
1 3 1
0 5 5
Sample Output
3
思路
带权并查集的应用,输入d x y 表示 x 的祖先与 y 的祖先的关系为 d,可直接看作 x 与 y 的关系为 d。
1、find( ) 函数寻找根节点的时候要不断更新 r[ ]数组
根据子节点与父节点的关系和父节点和爷爷节点的关系推到子节点和爷爷节点的关系。
由图示A为儿子,B为父亲,C为爷爷,则 r[ A->C ] = ( r[ A ] + r[ B ] ) % M

2、 Union的时候更新两棵树的关系
定义:fx 为 x的根节点, fy 为 y 的根节点,联合时,使得fa[ fx ] = fy;同时也要寻找 fx 和 fy 的关系,其关系为 r[fx] = (r[y] - r[x] + d + M) % M;  

在判断时,推测一句话是否是错的,可根据双方跟根节点的关系推知:如果 r[x] - r[y] + M) % M != d 那么这句话就是错的。

#include<stdio.h>    
#include<string.h>    
const int maxn = 50005;    
int fa[maxn],r[maxn];    
    
int find(int x,int M)    
{    
    if (fa[x] == x) return fa[x];    
    int tmp = fa[x];    
    fa[x] = find(fa[x],M);    
    r[x] = (r[tmp] + r[x]) % M;    
    return fa[x];    
}    
    
void unite(int x,int y,int d,int M)    
{    
    int fx = find(x,M),fy = find(y,M);    
    if (fx == fy)   return;    
    fa[fx] = fy;    
    r[fx] = (r[y] - r[x] + d + M) % M;    
}    
    
int main()    
{    
   // freopen("input.txt","r",stdin);    
    int M,N,K,x,y,d,i,res = 0;    
    scanf("%d%d%d",&M,&N,&K);    
    for (i = 0;i <= N;i++)   fa[i] = i,r[i] = 0;    
    while (K--)    
    {    
        scanf("%d%d%d",&d,&x,&y);    
        int fx = find(x,M),fy = find(y,M);    
        if (x > N || y > N || d >= M || d < 0)  res++;    
        else if (fx == fy)    
        {    
            if ((r[x] - r[y] + M) % M != d) res++;  
        }    
        else    
        {  
            unite(x,y,d,M);   
        }      
    }    
    printf("%d\n",res);    
    return 0;    
} 
┆ 凉 ┆ 暖 ┆ 降 ┆ 等 ┆ 幸 ┆ 我 ┆ 我 ┆ 里 ┆ 将 ┆ ┆ 可 ┆ 有 ┆ 谦 ┆ 戮 ┆ 那 ┆ ┆ 大 ┆ ┆ 始 ┆ 然 ┆
┆ 薄 ┆ 一 ┆ 临 ┆ 你 ┆ 的 ┆ 还 ┆ 没 ┆ ┆ 来 ┆ ┆ 是 ┆ 来 ┆ 逊 ┆ 没 ┆ 些 ┆ ┆ 雁 ┆ ┆ 终 ┆ 而 ┆
┆ ┆ 暖 ┆ ┆ 如 ┆ 地 ┆ 站 ┆ 有 ┆ ┆ 也 ┆ ┆ 我 ┆ ┆ 的 ┆ 有 ┆ 精 ┆ ┆ 也 ┆ ┆ 没 ┆ 你 ┆
┆ ┆ 这 ┆ ┆ 试 ┆ 方 ┆ 在 ┆ 逃 ┆ ┆ 会 ┆ ┆ 在 ┆ ┆ 清 ┆ 来 ┆ 准 ┆ ┆ 没 ┆ ┆ 有 ┆ 没 ┆
┆ ┆ 生 ┆ ┆ 探 ┆ ┆ 最 ┆ 避 ┆ ┆ 在 ┆ ┆ 这 ┆ ┆ 晨 ┆ ┆ 的 ┆ ┆ 有 ┆ ┆ 来 ┆ 有 ┆
┆ ┆ 之 ┆ ┆ 般 ┆ ┆ 不 ┆ ┆ ┆ 这 ┆ ┆ 里 ┆ ┆ 没 ┆ ┆ 杀 ┆ ┆ 来 ┆ ┆ ┆ 来 ┆

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号