B3695
MatchaNeko_nya · · 题解
建议先阅读扶苏的bitset浅谈
本文主要描述如何实现题目中所述操作。
我们用一个 bitset<30005> 的第
那么我们一个一个操作来看:
操作
我们观察一个序列 1 3 5 9 在一个 bitset<15> 中的映射:000000100010101
再观察这个序列所有元素都加上 100010101000000
你发现了什么?
对,就是左移,所以操作 bitset。
你是不是以为,我们建一个 bitset<m>,然后左移之后超出去的部分就为自动删掉?
这里有一个坑点:bitset<N> 中的 bitset<m>,怎么办?
我们可以给另一个 bitset<30005> 的 bitset 与上后一个 bitset,就能起到将不在
操作
相对操作
操作
交集是由同时在两个集合中的元素构成的,那么这恰好符合哪种位运算?——与运算 &。
所以操作 S[x]&S[y]。
操作
同理可得,并集是由在任意一个集合中的元素构成的,那么这就是或运算 |,操作 S[x]|S[y]。
操作
对称差是由只在其中一个集合的元素构成的,那么这就是异或运算 ^,得操作 S[x]^S[y]。
Tip: 如果不知道异或是什么的,记住:若两个布尔值相等,则它们的异或值为
至此,你就可以利用 STL AC 一道黄题了。
附代码:
#include <bitset>
#include <vector>
#include <iostream>
const int maxn=30005;
int n,m,q;
std::bitset<maxn> s[maxn];
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin>>n>>m>>q;
for(int i = 1,c,x;i<=n; i++){
for(std::cin>>c;c;--c){
std::cin>>x;
s[i].set(x-1,1);
}
}
for(int i = 0; i<m; i++) s[0].set(i,1);
for(int o,x,y;q;--q){
std::cin>>o>>x>>y;
if(o==1){
s[x]<<=y;
s[x]&=s[0];
}else if(o==2){
s[x]>>=y;
}else if(o==3){
std::cout<<(s[x]&s[y]).count()<<'\n';
}else if(o==4){
std::cout<<(s[x]|s[y]).count()<<'\n';
}else if(o==5){
std::cout<<(s[x]^s[y]).count()<<'\n';
}
}
return 0;
}