这题其实可以用链表随意乱搞……
将每个颜色做成一个链表(然而可以不用指针),链表里面存这些颜色的起始点、终止点、前继点、个数等信息
然后变颜色时就用启发式合并,将少的颜色接在多的颜色后面就可以了
……吗?
并不是,比如说我把颜色1染成颜色2,但是颜色2的个数小于颜色1的个数的话,那么颜色2接在颜色1后面。但是如果接下来找颜色2的链表时,它就不见了……
因此我们要加开一个belong数组,belong[x]=y表示颜色y的链表在x处,在启发式合并时如果把颜色a染成颜色b后面但是size[b]<size[a]的话,就交换belong[a]和belong[b],初始化时belong[x]=x
好了,代码如下:
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define N 1001000
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define repu(i,r,l) for(int i=r;i>=l;i++)
using namespace std;
int n,m,ans,belong[N],c[N],st[N],en[N],pre[N],size[N];
void change(int x,int y)
{
if (size[belong[x]]>size[belong[y]]) swap(belong[x],belong[y]);
if (size[belong[x]]==0) return;
x=belong[x],y=belong[y];
for (int i=en[x];i;i=pre[i])
{
if (c[i-1]==y) ans--;
if (y==c[i+1]) ans--;
}
for (int i=en[x];i;i=pre[i]) c[i]=y;
size[y]+=size[x],size[x]=0;
pre[st[x]]=en[y];
en[y]=en[x];
st[x]=en[x]=size[x]=0;
}
int main()
{
scanf("%d%d",&n,&m);
rep(i,1,n)
{
scanf("%d",&c[i]);
belong[c[i]]=c[i];
size[c[i]]++;
if (c[i]!=c[i-1]) ans++;
if (!st[c[i]]) st[c[i]]=i;
pre[i]=en[c[i]];en[c[i]]=i;
}
rep(i,1,m)
{
int typ,x,y;
scanf("%d",&typ);
if (typ==2) printf("%d\n",ans);
else
{
scanf("%d%d",&x,&y);
if (x==y) continue;
change(x,y);
}
}
return 0;
}