Link
对每个集合维护其(a_i)表示有多少数是(i)的倍数。显然这个(a)数组与可重集一一对应。
第一种操做我们先预处理出(d_{i,j})表示(i)是否为(j),那么就变成了把(d_v)赋给(a_x)。
第二种操作就变成了(a)相加。
第三种操作就变成了(a)相乘。((i|gcd(a,b)Leftrightarrow i|awedge i|b))
第四种操作答案就是(sumlimits_{v|u}a_umu(frac uv))。
因为我们只关心对(2)取模的结果,那么我们显然可以用bitset来做。
第一种操作依旧是预处理然后直接赋值。
第二种操作就是异或。
第三种操作就是与。
第四种操作我们可以先筛出莫比乌斯函数,再预处理(mu_{i,i*j}=mu(j)),然后答案就是(mu_vcap a_x),再看这个里面的(1)的个数就好了。
#include<bits/stdc++.h>
using namespace std;
namespace IO
{
char ibuf[(1<<21)+1],obuf[(1<<21)+1],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
void Put(char x){*oS++=x;if(oS==oT)Flush();}
int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using namespace IO;
const int N=100007,M=7007,lim=7000;
bitset<M>a[N],Mu,d[M],mu[M];
int main()
{
int n=read(),Q=read(),x,y,z;
for(Mu.set(),x=2;x*x<=lim;++x) for(y=1;x*x*y<=lim;++y) Mu[x*x*y]=0;
for(x=1;x<=lim;++x) for(y=1;x*y<=lim;++y) d[x*y][x]=1,mu[x][x*y]=Mu[y];
while(Q--)
switch(read())
{
case 1:x=read(),y=read(),a[x]=d[y];break;
case 2:x=read(),y=read(),z=read(),a[x]=a[y]^a[z];break;
case 3:x=read(),y=read(),z=read(),a[x]=a[y]&a[z];break;
case 4:x=read(),y=read(),Put(48+((a[x]&mu[y]).count()&1));break;
}
return Flush(),0;
}