题解:P9989 [Ynoi Easy Round 2023] TEST_69
前言
注意到 test_69 没有 69 个 test。
思路分析
我们知道,每次对于一个数取 gcd 时,如果这个数改变,那么至少减小至原来的 \(\frac{1}{2}\)。
然后考虑怎么判断区间每个数的 gcd 是否改变,不难发现维护区间 lcm,如果 k 是 区间 lcm 的倍数,那么区间里的数都不会改变。
问题又来了,维护初始序列的 lcm 可能炸 long long,又无法使用取模。
考虑只维护 lcm 是否 \(\ge v\),初始 lcm 均 \(\ge v\),如果递归过一次这个区间,那么 lcm 一定 \(\le v\),所以这样做不会影响复杂度。
fan fact:像这样递归求 lcm 的复杂度为 \(O(n \log n)\)。
代码实现
#include<bits/stdc++.h>
#define int __int128
using namespace std;
template<typename T> inline void read(T &a){
a=0;
char c=getchar();
bool flag=false;
while(!isdigit(c)){
if(c=='-') flag=true;
c=getchar();
}
while(isdigit(c)){
a=(a<<1)+(a<<3)+(c^48);
c=getchar();
}
a=(flag?-a:a);
}
template<typename T> inline void write(T a){
if(a<0) putchar('-'),a=-a;
if(a<10) putchar(a+'0');
else write(a/10),putchar(a%10+'0');
}
const int mod=1ll<<32;
int n,m,a[200005],op,l,r,k;
int val_sum[400005],val_lcm[400005],ls[400005],rs[400005],dcnt,rt;
void pushup(int x){
val_sum[x]=(val_sum[ls[x]]+val_sum[rs[x]])%mod;
if(!val_lcm[ls[x]] || !val_lcm[rs[x]]) val_lcm[x]=0;
else val_lcm[x]=val_lcm[ls[x]]/__gcd(val_lcm[ls[x]],val_lcm[rs[x]])*val_lcm[rs[x]];
}
void build(int l,int r,int &x){
x=++dcnt;
if(l==r){
val_sum[x]=val_lcm[x]=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,ls[x]);
build(mid+1,r,rs[x]);
pushup(x);
}
void modify(int l,int r,int ql,int qr,int k,int x){
if(ql<=l && r<=qr){
if(val_lcm[x] && k%val_lcm[x]==0) return;
if(l==r){
val_sum[x]=__gcd(val_sum[x],k);
val_lcm[x]=__gcd(val_lcm[x],k);
return;
}
}
int mid=(l+r)>>1;
if(ql<=mid) modify(l,mid,ql,qr,k,ls[x]);
if(qr>=mid+1) modify(mid+1,r,ql,qr,k,rs[x]);
pushup(x);
}
int query(int l,int r,int ql,int qr,int x){
if(ql<=l && r<=qr) return val_sum[x];
int mid=(l+r)>>1,ans=0;
if(ql<=mid) ans=(ans+query(l,mid,ql,qr,ls[x]))%mod;
if(qr>=mid+1) ans=(ans+query(mid+1,r,ql,qr,rs[x]))%mod;
return ans;
}
signed main(){
read(n),read(m);
for(int i=1;i<=n;i++){
read(a[i]);
}
build(1,n,rt);
for(int i=1;i<=m;i++){
read(op);
if(op==1){
read(l),read(r),read(k);
modify(1,n,l,r,k,rt);
}else{
read(l),read(r);
write(query(1,n,l,r,rt));
puts("");
}
}
return 0;
}