• 【ybt金牌导航6-2-1】【luogu P3201】梦幻布丁 / 启发式合并例题


    梦幻布丁

    题目链接:ybt金牌导航6-2-1 / luogu P3201

    题目大意

    有一些颜色块,然后它有时会把所有颜色改成另一种颜色,有时会询问你现在有多少个颜色段。一个颜色段就是一段相同颜色的连续颜色块。

    思路

    那这个我们可以发现,其实每次更改就是把一些部分合并。
    合并了之后,就不会再分开。

    那我们可以用启发式合并,合并的时候,枚举个数少的,把它合并到大的当中,以减少时间。

    那它是如何合并的呢?
    假设我们已经可以找到某种颜色的所有块,然后来看。
    如果它的左边是要更改成的颜色,那颜色段就减一。如果它的右边是更改成的颜色,那么颜色段就减一。(两个同时发生就减二)

    那一开始我们可以求出一开始的颜色段数。

    然后现在就是看如何找到某种颜色的所有块,然后这个其实可以用链表来维护。

    然后就可以了。

    代码

    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    
    int n, m, a[100001], b[1000001], s[1000001];
    int le[1000001], ans, op, x, y, nxt[1000001];
    int son[1000001];
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", &a[i]);
    		b[a[i]] = a[i];//记录它所在链的颜色
    		s[a[i]]++;//记录这个颜色的个数
    		nxt[i] = le[a[i]];//链表连向它之前的头
    		if (!le[a[i]]) {
    			son[a[i]] = i;//记录这个颜色的链的末端
    		}
    		le[a[i]] = i;//链表头设为它
    		if (a[i] != a[i - 1]) ans++;//求出初始颜色段
    	}
    	
    	for (int i = 1; i <= m; i++) {
    		scanf("%d", &op);
    		if (op == 1) {
    			scanf("%d %d", &x, &y);
    			
    			if (x == y) continue;//同一个颜色相互转换等于没有转
    			
    			if (s[b[x]] > s[b[y]]) swap(b[x], b[y]);
    			//启发式合并,个数小的合并到个数大的
    			
    			if (!s[b[x]]) continue;//最小的那个没有,就相当于没有合并
    			
    			x = b[x];//找到它们现在的颜色
    			y = b[y];
    			for (int i = le[x]; i; i = nxt[i]) {
    				if (a[i + 1] == y) ans--;//左边变成了一样的
    				if (a[i - 1] == y) ans--;//右边变成了一样的			}
    			
    			for (int i = le[x]; i; i = nxt[i]) {
    				a[i] = y;//改颜色
    			}
    			
    			nxt[son[y]] = le[x];
    			//把两个链连在一起(前面的链尾的下一个是后面的头)
    			son[y] = son[x];//链尾变成后面的链尾
    			
    			le[x] = 0;//清空
    			son[x] = 0;
    			s[y] += s[x];//颜色个数增加
    			s[x] = 0;
    		}
    		else {
    			printf("%d
    ", ans);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    C语言-数组指针
    关于知网文章下载
    SpringBoot静态资源文件存放位置
    ArchLinux安装的vscode修改插件源
    I/O复用的高级应用三:同时处理TCP和UDP服务
    Windows查看动态库/静态库位数的方法
    VS 窗口程序没有输出时
    Windows下编译Boost
    VS设置C++代码注释模板
    No Target Architecture
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_6-2-1.html
Copyright © 2020-2023  润新知