Description
N個布丁擺成一行,進行M次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別爲1,2,2,1的四個布丁一共有3段顏色.
Input
第一行給出N,M表示布丁的個數和好友的操作次數. 第二行N個數A1,A2...An表示第i個布丁的顏色從第三行起有M行,對於每個操作,若第一個數字是1表示要對顏色進行改變,其後的兩個整數X,Y表示將所有顏色爲X的變爲Y,X可能等於Y. 若第一個數字爲2表示要進行詢問當前有多少段顏色,這時你應該輸出一個整數. 0
Output
針對第二類操作即詢問,依次輸出當前有多少段顏色.
Sample Input
1 2 2 1
2
1 2 1
2
Sample Output
31
正解:鏈表啓發式合併。
——hzwer
複雜度證明很神奇。。感覺自己用鏈表還不熟啊。。
//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define il inline
#define RG register
#define ll long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
int size[1000010],head[1000010],st[1000010],f[1000010],nt[100010],a[100010],n,m,tot,ans;
il int gi(){
RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
}
il void solve(RG int x,RG int y){
for (RG int i=head[x];i;i=nt[i]){
if (a[i+1]==y) ans--; if (a[i-1]==y) ans--;
}
for (RG int i=head[x];i;i=nt[i]) a[i]=y;
nt[st[x]]=head[y],head[y]=head[x];
size[y]+=size[x],head[x]=st[x]=size[x]=0;
return;
}
il void work(){
n=gi(),m=gi(); RG int x,y; for (RG int i=1;i<=n;++i) a[i]=gi();
for (RG int i=1;i<=n;++i){
f[a[i]]=a[i],size[a[i]]++;
if (a[i]!=a[i-1]) ans++;
if (!head[a[i]]) st[a[i]]=i;
nt[i]=head[a[i]],head[a[i]]=i;
}
for (RG int i=1;i<=m;++i){
RG int type=gi();
if (type==1){
x=gi(),y=gi(); if (x==y) continue;
if (size[f[x]]>size[f[y]]) swap(f[x],f[y]);
x=f[x],y=f[y]; if (!size[x]) continue; solve(x,y);
}else printf("%d\n",ans);
}
return;
}
int main(){
File("pudding");
work();
return 0;
}