[bzoj1483]:[HNOI2009]梦幻布丁
来自FallDream的博客,未经允许,请勿转载,谢谢。
N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.
n,m<=10^5 ai<=10^6
第一眼觉得可以平衡树+启发式合并
但是想了想直接启发式合并就行了 用链表链起来即可。
复杂度最坏nlogn
#include<iostream> #include<cstdio> #define rint register int #define MN 100000 using namespace std; inline int read() { int x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9')x = x * 10 + ch - '0',ch = getchar(); return x; } int n,m,ans=1,a[MN+5],head[MN*10+5],s[MN*10+5],size[MN*10+5],cnt=0; struct edge{int x,next;}e[MN*35+5]; inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;} inline void Merge(int x,int y) { x=s[x];y=s[y];size[y]+=size[x]; for(rint i=head[x];i;i=e[i].next) ans-=(e[i].x!=1&&a[e[i].x-1]==y)+(e[i].x!=n&&a[e[i].x+1]==y); for(rint i=head[x];i;i=e[i].next) ins(y,e[i].x),a[e[i].x]=y; head[x]=size[x]=0; } int main() { n=read();m=read(); for(rint i=1;i<=n;++i) a[i]=read(),s[a[i]]=a[i]; for(rint i=1;i<=n;++i) ++size[a[i]],ins(a[i],i),ans+=(i!=1&&a[i]!=a[i-1]); for(rint i=1;i<=m;++i) { int op=read(); if(op==1) { int x=read(),y=read();if(x==y) continue; if(size[s[x]]>size[s[y]]) swap(s[x],s[y]); Merge(x,y);s[x]=0; } else printf("%d\n",ans); } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream