题目
题目链接
题意
给你一个数列代表不同的颜色(可以修改)。
询问一段区间内有多少种颜色。
题解
很容易想到的就是线段树来维护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]));}}
}