题目描述
N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.
输入格式
第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0
输出格式
针对第二类操作即询问,依次输出当前有多少段颜色.
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+5,M=6e6+5;
inline int read(){
int x=0; char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
return x;
}
int n,m;
int root[N],ls[M],rs[M],val[M],L[M],R[M],num;
#define mid ((l+r)>>1)
inline void pushup(int p){
val[p]=val[ls[p]]+val[rs[p]]-(R[ls[p]]+1==L[rs[p]]);
L[p]=L[ls[p]],R[p]=R[rs[p]];
}
void update(int &p,int l,int r,int pos,int d){
if(!p)p=++num;
if(l==r){ val[p]+=d; L[p]=R[p]=l; return; }
if(pos<=mid)update(ls[p],l,mid,pos,d);
else update(rs[p],mid+1,r,pos,d);
pushup(p);
}
void merge(int &u,int v,int l,int r){
if(!u||!v){ u|=v; return; }
if(l==r){ val[u]=1; L[u]=R[u]=l; return; }
merge(ls[u],ls[v],l,mid);
merge(rs[u],rs[v],mid+1,r);
pushup(u);
}
signed main(){
n=read(),m=read();
int Max=0,ans=0;
for(int i=1,x,lst=-1;i<=n;i++){
x=read(); ans+=(lst!=x);
lst=x; Max=max(Max,x);
update(root[x],1,n,i,1);
}
int x,y;
while(m--){
x=read();
if(x==1){
x=read(),y=read();
if(x==y)continue;
ans-=val[root[x]]+val[root[y]];
merge(root[y],root[x],1,n);
ans+=val[root[y]];
root[x]=0;
}else printf("%d
",ans);
}
}