蓝桥杯 修改数组 (巧用并查集)

题意: 给你一个长度为 n 的序列, 现在按以下方法修改序列: 

       1、依次修改 A1 A2 A3 A4 A5 ...... AN;

     2、当修改 Ai 时, 检查 A1 ~ Ai-1 是否出现过, 若出现过, 则Ai加1,若更新完的Ai仍然在A1 ~ Ai 出现过, 则继续加1,直到未出现过。

     输出最终序列。 1 <= n <= 100000,   1 <= Ai <= 1000000

解:  巧用并查集。  

    f[ i ] 表示当你访问到 i  这个数时 应该将它 换成什么。 

    一开始的时候 f[ i ] 都等于 i, 因为都还没被访问过。

   当你访问完 i 这个数, 你需要更新它的 f[ i ] 为 f[ i + 1 ];

   因为, 当你再次访问到 i 的时候, i 已经输出过了, 所以你需要输出 i + 1;

   但,你可能 i + 1也出现过了, 所以你 输出的是 f[ i + 1];

   

#include <bits/stdc++.h>
#define LL long long
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define mem(i, j) memset(i, j, sizeof(i))
#define pb push_back
using namespace std;

const int N = 1e6 + 5;
int f[N], a[N];
int Fin(int v) {
    return f[v] == v ? v : f[v] = Fin(f[v]);
}

int main() {
    rep(i, 1, N - 1) f[i] = i;/// 初始化, 指向自己
    int n; scanf("%d", &n);
    rep(i, 1, n) {
        scanf("%d", &a[i]);
        int nx = Fin(a[i]); /// 当前这个点, 指向的点
        a[i] = nx;
        f[a[i]] = Fin(a[i] + 1); /// 这个点,更新为下一个点指向的点
    }
    rep(i, 1, n - 1) printf("%d ", a[i]);
    printf("%d\n", a[n]);
    return 0;
}
View Code

 

posted on 2019-12-08 11:08  Willems  阅读(1157)  评论(0编辑  收藏  举报

导航