梦幻布丁 启发式合并板子

复制代码
//题意:将一段布丁染色,然后有两种操作,操作1将颜色为x的布丁全部染为y,操作2统计当前一共有多少段颜色
//思路:将x染色为y可以想到启发式合并,但是注意我们交换大小集合后,有可能最后合并本来应该剩下y集合的,但是却剩下了x集合
//      好在答案与你到底是x还是y无关(只统计颜色段数),只需要在叫到y的时候,将x(或y)合并到另一种颜色就好
#include<bits/stdc++.h>
using namespace std;
const int N = 101000;
const int M = 1010000;
vector<int> pos[M];
int n, m, a[N], ans;
void modify(int p, int col) {
        ans -= (a[p] != a[p - 1]) + (a[p] != a[p + 1]);
    a[p] = col;
        ans += (a[p] != a[p - 1]) + (a[p] != a[p + 1]);
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        pos[a[i]].push_back(i);//将每个位置归类进每个颜色集合
    }
    for (int i = 1; i <= n + 1; i++) ans += a[i] != a[i - 1];//统计不同颜色段数,因为算上了a[0],
                                                         //所以最终ans应该-1
    for (int i = 0; i < m; i++) {
        int op; scanf("%d", &op);
        if (op == 2) printf("%d\n", ans - 1);
        else {
            int x, y;
            scanf("%d%d", &x, &y);
            if (x == y) continue;
            if (pos[x].size() > pos[y].size()) swap(pos[x], pos[y]);//保证x为小集合,最后合并剩下到的集合一定是y
            
            if (pos[y].empty()) continue;
            int col = a[pos[y][0]];//查询集合y中的实际颜色

            for (int p : pos[x]) {
                modify(p, col);//因为pos[y]集合中的点颜色不一定是y,所以需要单独修改
                pos[y].push_back(p);//集合合并
            }
                
            pos[x].clear();

        }
    }
}
复制代码

 

posted @   Aacaod  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示