开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情
[HNOI2009] 梦幻布丁
题目描述
个布丁摆成一行,进行 次操作。每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色。
例如,颜色分别为 的四个布丁一共有 段颜色.
输入格式
第一行是两个整数,分别表示布丁个数 和操作次数 。
第二行有 个整数,第 个整数表示第 个布丁的颜色 。
接下来 行,每行描述一次操作。每行首先有一个整数 表示操作类型:
- 若 ,则后有两个整数 ,表示将颜色 的布丁全部变成颜色 。
- 若 ,则表示一次询问。
输出格式
对于每次询问,输出一行一个整数表示答案。
样例 #1
样例输入 #1
4 3
1 2 2 1
2
1 2 1
2
样例输出 #1
3
1
提示
样例 1 解释
初始时布丁颜色依次为 ,三段颜色分别为 。
一次操作后,布丁的颜色变为 ,只有 一段颜色。
数据规模与约定
对于全部的测试点,保证 ,。
提示
请注意,不保证颜色的编号不大于 ,也不保证 , 不是颜色的编号上限。
分析
这题是个板子题,是莫队根号分块的板子题,这题暴力显然是不行的啦,用pos来记录一下位置,然后分块求,使复杂度讲到nsqrt(n)。
代码
//Awwawa! Dis cold yis ratten buy Pikachu!
#include <bits/stdc++.h>
#define ll long long
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define vi vector<int>
#define pi pair<int, int>
#define mod 998244353
using namespace std;
const int N=100020;
const int M=1000010;
inline int read(){//快读
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int n,m;
int a[N];
vi pos[M];
int ans=0;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
pos[a[i]].pb(i);
}
for(int i=1;i<=n+1;i++){
ans+=(a[i]!=a[i-1]);
}
for(int i=1;i<=m;i++){
int op;
cin>>op;
if(op==2) cout<<ans-1<<endl;
else{
int x,y;
cin>>x>>y;
if(x==y) continue;
else{
if(pos[x].size()>pos[y].size()){
swap(pos[x],pos[y])
;
}
auto modify=[&](int p,int col){
ans-=(a[p]!=a[p-1])+(a[p]!=a[p+1]);
a[p]=col;
ans+=(a[p]!=a[p-1])+(a[p]!=a[p+1]);
};
int col=a[pos[y][0]];
for(auto p:pos[x]){
modify(p,col);
pos[y].pb(p);
}
}
pos[x].clear();
}
}
return (0-0);
}
希望能帮助到大家qaq!