【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;
}
原文地址:https://www.cnblogs.com/2020pengxiyue/p/9564672.html