P9989 TEST_69
题面
题解
经典的,注意到一个数被有效操作 \(O(\log V)\) 次后会变为 \(1\)。
注意到如果 \(a_k|x\),则这次修改对 \(a_k\) 无效。我们设法只进行有效的修改。
注意到如果 \(\mathrm{lcm}(a_l,a_{l+1},\cdots,a_r)|x\),则修改对 \(a_l,a_{l+1},\cdots,a_r\) 均无效。
那么我们用线段树维护区间 \(\mathrm{lcm}\),修改时在线段树上 dfs,遇到无效区间就跳过。
这样,进行一次有效操作用时 \(O(\log n)\),一共 \(O(n\log V)\) 次有效操作,总复杂度 \(O(n\log V\log n)\)。
Code
#include<bits/stdc++.h>
using namespace std;
const long long MAXLCM=1.5e18;
struct node{
long long lcm;
unsigned int sum;
inline node operator+(const node &b)const{
node c; c.sum=sum+b.sum;
long long h=__gcd(b.lcm,lcm);
if(MAXLCM/(lcm/h)<b.lcm) c.lcm=MAXLCM;
else c.lcm=lcm/h*b.lcm;
return c;
}
};
node s[800005];
void build(int p,int l,int r){
if(l==r){
cin>>s[p].lcm; s[p].sum=s[p].lcm; return;
}
int m=l+r>>1;
build(p<<1,l,m); build(p<<1|1,m+1,r); s[p]=s[p<<1]+s[p<<1|1];
}
void update(int p,int l,int r,int x,int y,long long v){
if(x>r||y<l) return;
if(v%s[p].lcm==0) return;
if(l==r){
s[p].sum=s[p].lcm=__gcd(v,s[p].lcm); return;
}
int m=l+r>>1;
update(p<<1,l,m,x,y,v); update(p<<1|1,m+1,r,x,y,v);
s[p]=s[p<<1]+s[p<<1|1];
}
unsigned int query(int p,int l,int r,int x,int y){
if(x>r||y<l) return 0; if(x<=l&&r<=y) return s[p].sum;
int m=l+r>>1; return query(p<<1,l,m,x,y)+query(p<<1|1,m+1,r,x,y);
}
int n,q;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>n>>q; build(1,1,n);
while(q--){
int tp,l,r; long long x;
cin>>tp>>l>>r;
if(tp==1){
cin>>x; update(1,1,n,l,r,x);
}else cout<<query(1,1,n,l,r)<<'\n';
}
return 0;
}