启发式合并

前去学习了一下启发式合并当然并查集的还没学呢。。

所谓的启发式合并就是合并的时候把小的东西往大的东西里面一个一个插?

去做了一下网上的例题梦幻布丁,发现set的功能真是挺强大的(有机会好好学学)。

我比较蒙逼的就是dalao们的fa数组,后来了解了,解释在代码里,挺浅显易懂的emm大概?

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,m,ans;
int fa[1000005],v[100005];
set<int> a[1000005];
inline long long read() {
    long long x = 0;
    long long f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')
            f = -f;
        c = getchar();
    }
    while (c <= '9' && c >= '0') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
} 
void solve(int x,int y){ 
    for(set<int>::iterator i=a[x].begin();i!=a[x].end();i++){
        if(v[*i-1]==y)ans--; 
        if(v[*i+1]==y)ans--;
        a[y].insert(*i); 
    } 
    for(set<int>::iterator i=a[x].begin();i!=a[x].end();i++){
        v[*i]=y; 
    }
    a[x].clear(); 
} 
int main(){
     n=read();m=read();
    for(int i=1;i<=n;i++) v[i]=read();
    for(int i=1;i<=n;i++){
        fa[v[i]]=v[i];
        if(v[i]!=v[i-1]) ans++;  //有颜色间隔
        a[v[i]].insert(i);  //当前下标扔对应颜色的框里 
    }
    for(int i=1;i<=m;i++) {
        int o=read();
        if(o==2)printf("%d\n",ans);
        else{
            int x=read(),y=read();
            if(x==y)continue; 
            //cout<<fa[x]<<endl<<fa[y]<<endl; 
            if(a[fa[x]].size()>a[fa[y]].size()){
               swap(fa[x],fa[y]); //fa[i]是用于存储值为i的数位置存在了S{fa[i]}集合中,所以合并时也不要忘记了修改fa[i] 
            } //避免下次合并时S{y}为空 
            x=fa[x],y=fa[y];
            solve(x,y); 
        } 
    } 
} 
posted @ 2019-10-31 16:45  wilxx  阅读(154)  评论(0编辑  收藏  举报