大致题意
你需要维护一种数据结构,满足可以进行以下操作:
- 合并两个元素所在集合
- 查询一个元素所在集合有多少个类型为指定类型的元素
大体思路
一道很板的题。
看到第一种操作就会想到并查集,由第二种操作想到启发式合并。
怎么合并?可以用一个 map 数组 m p i , j mp_{i,j} mpi,j 来记录第 i i i 个集合,类型(即题目中的 C i C_i Ci)为 j j j 的学生数,则合并就很简单了:
f[x] = y;
for(auto v: mp[x]) mp[y][v.first] += v.second;
一个小细节,我们可以把元素少的集合合并到元素多的集合,这样 for
的时候就可以减少复杂度,所以只需加上这句话:
if(mp[x].size() > mp[y].size()) swap(x, y);
并查集总代码:
int f[200007];
map<int, int> mp[200007];
int find(int x) {
if(f[x] == x) return x;
return f[x] = find(f[x]);
}
inline void join(int x, int y) {
x = find(x), y = find(y);
if(x == y) return ;
if(mp[x].size() > mp[y].size()) swap(x, y);
f[x] = y;
for(auto v: mp[x])
mp[y][v.first] += v.second;
}