BZOJ 1483 梦幻布丁( 启发式合并)

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。

n,m<=1000000

Output

针对第二类操作即询问,依次输出当前有多少段颜色.

Sample Input

4 3
1 2 2 1
2
1 2 1
2

Sample Output

3
1

用到了启发式合并,就是小的数据结构合并到了大的数据结构里

#include <stdio.h>
#include <set>

const int MAXN = 1000005;
using namespace std;

set<int> st[MAXN];
int col[MAXN],fa[MAXN];
int ans;
void solve(int a,int b)
{
    for(set<int>::iterator i = st[a].begin(); i != st[a].end(); i++) {
        if(col[*i - 1] == b) ans--;
        if(col[*i + 1] == b) ans--;
        st[b].insert(*i);
    }
    for(set<int>::iterator i = st[a].begin(); i != st[a].end(); i++) col[*i] = b;
    st[a].clear();
}
int main(void)
{
    int n,m;
    ans = 0;
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++) {
        scanf("%d",&col[i]);
        fa[col[i]] = col[i];
        st[col[i]].insert(i);
        if(col[i] != col[i - 1]) ans++;
    }
    int op;
    int a,b;
    while(m--) {
        scanf("%d",&op);
        if(op == 2) printf("%d\n",ans);
        else {
            scanf("%d%d",&a,&b);
            if(a != b) {
                if(st[fa[a]].size() > st[fa[b]].size()) {
                    swap(fa[a],fa[b]);
                }
                a = fa[a],b = fa[b];
                solve(a,b);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/81270036
今日推荐