题目
题意
给你一个数列代表不同的颜色(可以修改)。
询问一段区间内有多少种颜色。
题解
很容易想到的就是线段树来维护bitset。
这里为了练习,使用分块维护bitset。
* 事实上线段树可以看成是无限分块。*
修改的时候直接暴力将被修改位置所在的块重新计算,形成新的bitset。
查询的时候,直接按块合并bitset即可。
注意细节:由于bitset不能开太大,因此有必要将给出的颜色进行离散化。
我采用的方法是使用unordered_map进行离散化,简单易行。
代码
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
int n,m,L,R;
int a[10007];
bitset<12007> block[107];
bitset<12007> now;
int Base = 100;
unordered_map<int,int> mpid;
inline int getid(int x){
if(mpid.count(x)) return mpid[x];
return mpid[x] = mpid.size()+1;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i){
if(i % Base == 0 && i != 0) {
block[i/Base-1] = now;
now.reset();
}
scanf("%d",&a[i]);
now.set(getid(a[i]));
}
block[n/Base] = now;
char op;
while(m--){
scanf(" %c%d%d",&op,&L,&R);
if(op == 'Q'){
now.reset();
for(;L % Base != 0 && L <= R;++L){
now.set(getid(a[L]));
}
for(;(R+1) % Base != 0 && R >= L;--R){
now.set(getid(a[R]));
}
if(L >= R) {
printf("%d\n",now.count());
continue;
}
int bl = L / Base,br = R / Base;
for(;bl <= br;++bl)
now |= block[bl];
printf("%d\n",now.count());
}
else {
a[L] = R;
int bl = L / Base;
block[bl].reset();
for(int i = bl*Base;i < (bl+1)*Base;++i)
block[bl].set(getid(a[i]));
}
}
}