【HNOI 梦幻糖果】| 区间染色 | 并查集 | 启发式合并 | 重链剖分)

//HNOI 梦幻糖果
//题意:n个布丁,m个颜色
//op1:把一个颜色的补丁全部变成另一种颜色
//op2:询问连续的颜色段个数
//表示方法:数组表示所有颜色,单链表表示颜色编号,让他们合并糖果
//启发式合并:元素少的合并到元素多的集合上

#include <cstdio>
#include <algorithm>
#include <cstring>

constexpr int NN{(int)(1e5)},MM{(int)(int)(1e6)};
int N,M,Q,op,ans = 0,h[MM],to[NN+1],ne[NN+1],tot,color[NN+1],sz[MM],p[MM];
inline void add(int u,int v){to[tot] = v,ne[tot] = h[u],h[u] = tot++;++sz[u];}
void merge(int &x,int &y){
	if(x == y)return;
	if(sz[x] > sz[y])std::swap(x,y);
	int i,j;
	for(i = h[x];~i;i = ne[i])
		j = to[i],ans-=(int)(color[j-1] == y)+(int)(color[j+1] == y);
	for(i = h[x];~i;i = ne[i])color[(j = to[i])] = y;
	ne[i] = h[y],h[y] = h[x],h[x] = -1;
	sz[y] += sz[x],sz[x] = 0;
}
int main(void){
	scanf("%d%d",&N,&M);
	memset(h,-1,sizeof h);
	int i;
	for(i = 1;i <= N;++i){
		scanf("%d",color[i]);
		ans += (int)(color[i] == color[i-1]);
		add(color[i],i);
	}
	for(i = 0;i < M;++i)p[i] = i;
	scanf("%d",&Q);
	while(Q--){
		scanf("%d",&op);
		if(op == 2)printf("%d\n",ans);
		else{
			int x,y;scanf("%d%d",&x,&y);
			merge(p[x],p[y]);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值