zoukankan      html  css  js  c++  java
  • 【HNOI2009】梦幻布丁

    题目描述

    N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色。

    输入输出格式

    输入格式

    第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0

    输出格式

    针对第二类操作即询问,依次输出当前有多少段颜色.

    数据范围

    (1le n,mle100,000); (0<A_i,x,y<1,000,000)

    题解

    起初用的线段树维护,可是如果被卡的话,时间复杂度就变成了(O(n^2log_2n))了,所以,看了Hzwer大佬的博客后知道要用链表来解决,我们可以发现,对于一种颜色的操作,是把所有相同颜色都进行改变,所以我们把每种颜色都开一条链来维护,对于每次操作都是将两条链合并,一般的合并时间复杂度是(O(n))的,所以我们要考虑启发式合并,每次我们都会使该条链的长度变为原长度的两倍以上,所以,我们最多只会合并(log_2n)次,但是,这样我们就会发现,我们每次合并后颜色可能会发生错位,我们需要利用一个数组来记录这种错位。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 100005, MAXM = 1000005;
    int color[MAXN], ft[MAXM], Head[MAXM], Next[MAXN], Stern[MAXM], Size[MAXM];
    int ans = 0;
    
    void Merge(int x, int y)
        {
            for(int i = Head[x]; i != -1; i = Next[i])
                {
                    if(color[i + 1] == y) ans --;
                    if(color[i - 1] == y) ans --;	
                }
            for(int i = Head[x]; i != -1; i = Next[i])	color[i] = y;
            Next[Stern[x]] = Head[y], Size[y] += Size[x], Head[y] = Head[x];
            Head[x] = -1 ,Stern[x] = Size[x] = 0;
            return; 
        }
    
    
    int main()
    {
        int opt, x, y;
        memset(Head, -1, sizeof(Head));
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++ i)
            {
                scanf("%d", &color[i]);
                ft[color[i]] = color[i];
                if(color[i] != color[i - 1]) ans ++;
                if(Head[color[i]] == -1)	Stern[color[i]] = i;
                Next[i] = Head[color[i]], Head[color[i]] = i, Size[color[i]] ++;
            }
        for(int i = 1; i <= m; ++ i)
            {
                
                scanf("%d", &opt);
                if(opt == 2) printf("%d
    ", ans);
                else{
                    scanf("%d%d", &x, &y);
                    if(x == y) continue;
                    if(Size[ft[x]] > Size[ft[y]])	swap(ft[x], ft[y]);
                    x = ft[x], y = ft[y];
                    if(Size[x] == 0) continue;
                    Merge(x, y);
                }
            }
        return 0;
    }
    
  • 相关阅读:
    leecode练习--804、唯一摩尔斯密码词
    leecode练习--832、翻转图像
    leecode练习--561、数组拆分Ⅰ
    leecode练习--942、增减字符串匹配
    第二十篇 编程语言分类
    《英语学习》记录
    《视频笔记》记录
    《爬虫》爬取可用的免费IP
    《读书笔记》记录
    数据结构与算法之美
  • 原文地址:https://www.cnblogs.com/2020pengxiyue/p/9564672.html
Copyright © 2011-2022 走看看