题目描述
N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.
输入描述
第一行给出N,M表示布丁的个数和好友的操作次数.
第二行N个数A1,A2...An表示第i个布丁的颜色从
第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y.
若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0
输出描述
针对第二类操作即询问,依次输出当前有多少段颜色.
示例一
输入
4 3
1 2 2 1
2
1 2 1
2
输出
3
1
说明
初始时布丁颜色依次为1,2,2,1,三段颜色分别为 [1, 1], [2, 3], [4, 4]。
一次操作后,布丁的颜色变为1,1,1,1,只有[1,4] 一段颜色。
解题思路
首先将相同颜色的布丁放在同一个数组里面,在放入布丁的同时进行判断,判断当前布丁颜色是否与前一个布丁颜色是一样的,如果不同,则段数加一。
当对布丁颜色进行改变时候,我们利用等效思想,将布丁数少的颜色换成布丁数多的颜色,再写一个change函数来模拟,改变颜色之后,分别将当前颜色段与前一段和后一段颜色比较,判断它们是否会相同,如果相同,段数减一。
模拟之后得到段数,再进行实际的颜色改变,将改变颜色后的布丁都加进相同颜色的布丁数组,再将颜色改变前的布丁数组清空。
实现代码
话不多说,上代码
#include<iostream>
#include<vector>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
#define rep(j,m) for(int j = 0;j < m;j++)
const int N=1e6+10,mod=1e9-7,INF=1e9+10;
int n,m;
int ans = 1;
int col[N];
vector<int> g[N];
void change(int a,int b){//颜色a和颜色b
for(int i:g[a]){
if(i-1 >= 0 and col[i-1] == b)ans--;//用于判断颜色发生变化之后,前后布丁颜色是否一致
if(i+1 < n and col[i+1] == b)ans--;
}
}
int main()
{
cin >> n >> m;
rep(i,n){
cin >> col[i];
g[col[i]].push_back(i);//将布丁的颜色存入对应的数组里面
if(col[i] != col[i-1] and i > 0)ans++;//如果当前布丁颜色与前一个布丁颜色不一样,则ans++
}
int num = 0;//用于统计有多少种颜色
rep(i,n){
if(!g[i].empty())num++;
}
rep(j,m){
int op;
int x,y;
cin >> op;
if(op==1){
cin >> x >>y;
if(x == y)continue;//当变化前后布丁颜色相同,则不做出改变
int a,b;
if(g[x].size() > g[y].size()){//确保a存的都是布丁数较少的颜色,以此提高交换效率
a = y;b = x;
}else{
a = x;b = y;
}
change(a,b);//将颜色x换为颜色y与颜色y换为x是等效的
for(int i:g[x])col[i]=y;//进行交换操作
g[y].insert(g[y].end(),g[x].begin(),g[x].end());//进行合并
g[x].clear();//清空颜色x的布丁
}
if(op==2){
cout << ans << endl;
}
}
return 0;
}
希望大家都能顺利AC!!!