链接 点击打开链接
有n(n<=1000)个集合,每个集合有m(m<=10000)个数,每个数的范围(<=10000)。
有q(q<=200000)个询问,每次询问两个数a,b,问是否存在集合包含这两个数。
我们对所有的集合进行分组,因为int最多32位,所以每一组中有32个集合,总共不超过32组。
因为数的大小不超过10000。a【i】【j】表示i这个数在第j组集合的情况。
例如:
10在第一组(一组里面又32个集合)的情况为13。即a【10】【0】=13。
13= 1101(十进制)表示10在第一组的第0个集合,第2个集合和第3个集合出现。
11在第一组(一组里面又32个集合)的情况为5。即a【11】【0】=5。
5= 0101(十进制)表示11在第一组的第0个集合和第2个集合出现。
那么 a【10】【0】&a【11】【0】>0.说明10和11在同一个集合出现。
所以我们枚举每一组的情况。
这里用2种位运算 | ,&,都是二进制下的运算。
x&y>0 说明x,y在二进制下有一位都是1。
x=x|(1<<j)把x的第j位变成1。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
int a[10010][35];
int main()
{
int n,m,q,x;
while ( scanf( "%d", &n)==1 )
{
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
{
scanf( "%d", &m );
while ( m-- )
{
scanf( "%d", &x );
a[x][i/32]|=(1<<i%32); // 把a[x][i/32]这个数的第i%32位变成1.
}
}
scanf( "%d", &q );
while ( q-- )
{
int x,y;
scanf( "%d%d", &x, &y );
for(int i=0;i<32;i++)
{
if(a[x][i]&a[y][i])
{
printf( "Yes\n" );
goto out;
}
}
printf( "No\n" );
out:;
}
}
return 0;
}