BZOJ 1483 梦幻布丁

时间:2023-03-08 19:40:26

Description

\(N\)个布丁摆成一行,进行\(M\)次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为\(1,2,2,1\)的四个布丁一共有\(3\)段颜色.

Input

第一行给出\(N,M\)表示布丁的个数和好友的操作次数. 第二行\(N\)个数\(A_{1},A_{2},...,A_{n}\)表示第\(i\)个布丁的颜色从第三行起有\(M\)行,对于每个操作,若第一个数字是\(1\)表示要对颜色进行改变,其后的两个整数\(X,Y\)表示将所有颜色为\(X\)的变为\(Y\),\(X\)可能等于\(Y\). 若第一个数字为\(2\)表示要进行询问当前有多少段颜色,这时你应该输出一个整数。

Output

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

Sample Input

4 3

1 2 2 1

2

1 2 1

2

Sample Output

3

1

直接用vector写。\(vec_{i}\)记录每个元素存在的区间,暴力合并区间即可。

#include<cstdio>
#include<cstdlib>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,len,pud[100010];
struct node { int l,r; };
vector <node> pos[1000010]; bool cmp(node a,node b) { return a.l > b.l; } void deal()
{
node temp; int i,j;
for (i = 1;i<=n;i++)
{
temp.l = i;
j = i;
while (pud[j+1] == pud[i]) j++;
temp.r = j; pos[pud[i]].push_back(temp); i = j;
}
} void change()
{
int a,b,i; scanf("%d %d",&a,&b);
if (a == b) return;
int nn1 = pos[a].size(),nn2 = pos[b].size(),fact;
if (nn1 == 0) return;
vector <node> :: iterator p;
for (i = 0;i<nn1;i++) pos[b].push_back(pos[a][i]);
pos[a].clear();
sort(pos[b].begin(),pos[b].end(),cmp);
for (p = pos[b].begin();p<pos[b].end()-1;p++)
while (p+1 < pos[b].end()&&(*p).r == (*(p+1)).l-1)
(*p).r = (*(p+1)).r,pos[b].erase(p+1);
fact = pos[b].size(); len = len+fact-nn1-nn2;
} int main()
{
freopen("1483.in","r",stdin);
freopen("1483.out","w",stdout);
scanf("%d %d",&n,&m);
int i;
for (i = 1;i <= n;i++)
{
scanf("%d",pud+i);
if (pud[i] != pud[i-1]) len++;
}
deal();
while (m--)
{
scanf("%d",&i);
switch (i)
{
case 1: change();break;
default: printf("%d\n",len);break;
}
}
return 0;
}