Skip to content

14235: 【原4235】不等的数

题目

题目描述

author: fur 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4235

相等的数

题目描述

现在有\(n\)个数,其构成序列\({a_i}\)(0-base),它们之间也有大小关系,对于每个数我们都能知道一个大于等于它的数,对于第\(i\)个数我们知道第\(g_i\)个数是大于等于它的,即\(a_i\leq a_{g_i}\)
碰巧的是,序列\({g}\)中\(0\)到\(n-1\)每个数出现且恰好出现一次
当然,大小关系如同我们所学的那样是具有传递性的
现在我们有能力每次交换序列\({g}\)中的两个数,即\(swap(g_x,g_y)\)
问至少需要交换多少次才能保证这个序列\({a}\)中所有数相等

输入格式

第一行一个数\(n\),表示序列长度
第二行\(n\)个数,表示序列\({g}\)

输出格式

一个数表示不同数值的数目

样例输入1

4
1 2 3 0

样例输出1

0

样例输入2

4
1 0 2 3

样例输出2

2

数据规模

对于20%的数据有
\(n\leq20\)
对于50%的数据有
\(n\leq1000\)
对于70%的数据有
\(n\leq20000\) 对于100%的数据有
\(n\leq100000\)

zqy2018's solution

/*
    Hint: Disjoint set
*/
#include <cstdio>
#define INF 2000000000
using namespace std;
typedef long long ll;
int read(){
    int f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
    while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
    return f * x; 
}
int n, g[100005], fa[100005], siz[100005], tot;
int Find(int x){
    return (fa[x] == x ? x: (fa[x] = Find(fa[x])));
}
void Union(int x, int y){
    int u = Find(x), v = Find(y);
    if (u == v) return ;
    if (siz[u] < siz[v])
        fa[u] = v, siz[v] += siz[u];
    else 
        fa[v] = u, siz[u] += siz[v];
    --tot;
}
void init(){
    n = read();
    tot = n;
    for (int i = 1; i <= n; ++i)
        fa[i] = i, siz[i] = 1;
    for (int i = 1; i <= n; ++i)
        g[i] = read() + 1, Union(i, g[i]);
}
void solve(){
    printf("%d\n", tot - 1);
}
int main(){
    init();
    solve();
    return 0;
}