zoukankan      html  css  js  c++  java
  • 蓝桥杯 修改数组 (巧用并查集)

    题意: 给你一个长度为 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
    ", a[n]);
        return 0;
    }
    View Code
    一步一步,永不停息
  • 相关阅读:
    【[CQOI2015]选数】
    杜教筛
    【[CQOI2009]跳舞】
    【简单的数学题】
    【[SDOI2013]泉】
    【[AHOI2013]差异】
    【[HEOI2016/TJOI2016]序列】
    【[SDOI2008]Sandy的卡片】
    linux系统编程之信号(一)
    linux系统编程之进程(五)
  • 原文地址:https://www.cnblogs.com/Willems/p/12005032.html
Copyright © 2011-2022 走看看