把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3201 [HNOI2009] 梦幻布丁

题面传送门
启发式合并大法好!
你会发现这道题可以暴力合并。
然而数据稍微用心一点就卡掉了。
然后你可以试图优化一下,比如合并时把小的合并到大的上面去。
结果就过了。
这样复杂度上界是\(O(nlogn)\),具体证明在这篇题解里有。
代码实现:

#include<cstdio>
#include<cstring>
int n,m,k,x,y,z,a[100039],siz[1000039],ans,cur,fa[1000039];
struct yyy{int to,z;}tmp;
struct ljb{
	int head,h[1000039];
	yyy f[2000039];
	inline void add(int x,int y){
		f[++head]=(yyy){y,h[x]};
		h[x]=head;
	}
}s;
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline void hebing(int x,int y){
	cur=s.h[x];
	while(cur!=-1){
		tmp=s.f[cur];
		ans-=(a[tmp.to-1]==y)+(a[tmp.to+1]==y);
		cur=tmp.z;
	}
	cur=s.h[x];
	while(cur!=-1){
		tmp=s.f[cur];
		a[tmp.to]=y;
		s.add(y,tmp.to);
		cur=tmp.z;
	}
	siz[y]+=siz[x];
	siz[x]=0;
	s.h[x]=-1;
}
int main(){
	memset(s.h,-1,sizeof(s.h));
	register int i;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&a[i]),s.add(a[i],i),siz[a[i]]++,fa[a[i]]=a[i];
	for(i=1;i<=n;i++) if(a[i]!=a[i-1]) ans++;
	for(i=1;i<=m;i++){
		scanf("%d",&x);
		if(x==1){
			scanf("%d%d",&x,&y);
			if(x==y) continue;
			if(siz[fa[x]]>siz[fa[y]])swap(fa[x],fa[y]);
			if(!siz[fa[x]])continue;
			hebing(fa[x],fa[y]);
		}
		else printf("%d\n",ans);
	}
}
posted @ 2020-10-05 15:01  275307894a  阅读(47)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end