【BZOJ1483】【HNOI2009】梦幻布丁

题意

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

题解

注意可能出现把a改成b后再改回来的情况

首先一个最简单的暴力就是每个颜色用一个vector保存位置,修改时把所有要修改的布丁暴力插入到目标颜色的vector里。

然后注意到可以用启发式优化,修改时把小的插到大的里。

可以开一个数组$dic$记录每个颜色的真实颜色,初始时$dic[i]=i$

如果目标颜色比修改颜色小,那么就$swap(dic[a],dic[b])$

修改前先$a=dic[a],b=dic[b]$

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <stack>
using namespace std;
#define N 1000001
#define now q[a][i]
int fa[N],col[N],dic[N];
bool vis[N];
vector<int> q[N];
int main()
{
	int n,m,cnt;
	cin>>n>>m;
	cnt=n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&col[i]);
		q[col[i]].push_back(i);
		if(col[i]==col[i-1]) cnt--;
	}
	for(int i=1;i<N;i++) dic[i]=i;
	for(int i=1;i<=m;i++)
	{
		int opt,a,b;
		scanf("%d",&opt);
		if(opt==1)
		{
			scanf("%d%d",&a,&b);
			if(a==b) continue;
			bool flag=(q[dic[a]].size()>q[dic[b]].size());
			if(flag) swap(dic[a],dic[b]);
			a=dic[a],b=dic[b];
			for(int i=0;i<q[a].size();i++) cnt-=(col[now-1]==b)+(col[now+1]==b);//减去颜色变化后连成一段的情况
			for(int i=0;i<q[a].size();i++) 
			{
				col[now]=b;
				q[b].push_back(now);
			}
			q[a].clear();
		}
		else printf("%d\n", cnt);
	}
}

  

posted @ 2019-12-21 11:48  linzhuohang  阅读(243)  评论(0编辑  收藏  举报