传送门
本题考虑直接对每个
i
i
i求出所有满足
i
j
=
g
c
d
(
i
,
j
)
i^j=gcd(i,j)
ij=gcd(i,j)的
j
j
j,然后存在
g
g
g数组中,对于查询修改操作维护一个并查集即可,合并的时候采用启发式合并(小的往大的上合)
核心问题在于如何初始化 g g g数组,考虑到每个数的因子其实不多,不妨枚举因子即可,假设枚举的因子为 d d d, a = k d a=kd a=kd,那么 b = a x o r d b=a\,xor\,d b=axord,然后检验一下是否满足 g c d ( a , b ) = d gcd(a,b)=d gcd(a,b)=d即可,预处理复杂度为 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)。
int fa[maxn],a[maxn],sz[maxn];
vector<int>g[maxm];
unordered_map<int,int>cnt[maxn];
ll ans=0;
int fd(int rt){
return rt==fa[rt]?rt:(fa[rt]=fd(fa[rt]));
}
int main(){
FOR(i,1,maxm){
for(register int j=i;j<maxm;j+=i){
if((j^i)>=maxm || !(j^i) || (j^i)>=maxm)continue;
if(__gcd(j,j^i)==i){
g[j].push_back(j^i);
}
}
}
int n=rd(),m=rd();
FOR(i,1,n+1){
a[i]=rd();
fa[i]=i;
cnt[i][a[i]]++;
sz[i]=1;
}
while(m--){
int t=rd();
if(t==1){
int x=rd(),v=rd();
fa[x]=x;
cnt[x][v]++;
sz[x]=1;
a[x]=v;
}else if(t==2){
int x=rd(),y=rd();
int fx=fd(x),fy=fd(y);
if(fx!=fy){
if(sz[fx]>sz[fy])swap(fx,fy);
unordered_map<int,int>::iterator it1;
for(it1=cnt[fx].begin();it1!=cnt[fx].end();++it1){
FOR(i,0,g[it1->first].size()){
if(cnt[fy].count(g[it1->first][i]))ans+=1ll*it1->second*cnt[fy][g[it1->first][i]];
}
}
for(it1=cnt[fx].begin();it1!=cnt[fx].end();++it1)cnt[fy][it1->first]+=it1->second;
cnt[fx].clear();
sz[fy]+=sz[fx];
fa[fx]=fy;
}
}else{
int x=rd(),v=rd();
int fx=fd(x);
FOR(i,0,g[a[x]].size()){
ans-=cnt[fx][g[a[x]][i]];
}
cnt[fx][a[x]]--;
a[x]=v;
FOR(i,0,g[v].size()){
ans+=cnt[fx][g[v][i]];
}
cnt[fx][v]++;
}
printf("%lld\n",ans);
}
}