我永远喜欢珂朵莉~
我永远喜欢珂朵莉~
题解
首先,除去 
     
      
       
       
         x 
        
       
         = 
        
       
         1 
        
       
      
        x=1 
       
      
    x=1的情况,我们的一个数最多进行 
     
      
       
       
         l 
        
       
         o 
        
       
         g 
         
        
        
          a 
         
        
          i 
         
        
       
      
        log\,a_{i} 
       
      
    logai次除法,所以事实上我们是可以对每个数暴力进行除法的,通过树状数组来维护区间和。
 所以对于数进行修改方面我们的时间复杂度是 
     
      
       
       
         O 
        
        
        
          ( 
         
        
          n 
         
         
          
          
            log 
           
          
             
           
          
         
           2 
          
          
        
          n 
         
        
          ) 
         
        
       
      
        O\left(n\log^2\,n\right) 
       
      
    O(nlog2n)。
 但真正的问题在于我们如何快速地找到我们需要进行修改的数。
 由于一个数在 
     
      
       
       
         5 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          5 
         
        
       
      
        5\times 10^5 
       
      
    5×105以内,一个数最多会有 
     
      
       
       
         300 
        
       
      
        300 
       
      
    300个约数左右,我们不妨对于每个数建一棵 
     
      
       
       
         T 
        
       
         r 
        
       
         e 
        
       
         a 
        
       
         p 
        
       
      
        Treap 
       
      
    Treap,表示为这个数倍数的位置有哪些。放心, 
      
       
        
        
          1.22 
         
        
          G 
         
        
          B 
         
        
       
         1.22GB 
        
       
     1.22GB的空间再怎么也不会MLE
 我们每次操作就直接从 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x对应的 
     
      
       
       
         T 
        
       
         r 
        
       
         e 
        
       
         a 
        
       
         p 
        
       
      
        Treap 
       
      
    Treap中分裂出区间 
     
      
       
       
         [ 
        
       
         l 
        
       
         , 
        
       
         r 
        
       
         ] 
        
       
      
        [l,r] 
       
      
    [l,r],将里面的数除以 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x。
 但当我们除去这个 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x后可能影响 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai的其它约数,我们不可能一个一个地进行更改,不如我们改一下原来的定义,改为可能为这个数倍数的数。
 因为我们只有除法,所以一个数的约数集合只会不断减少,不会增加,所以我们就不用管加点,只在每次调用这个区间时将不符合条件的点去掉即可。
 同理,我们在操作后也会有相当一部分点变得不能并入原树,我们将可以并入的点拿出来建一棵新树后再合并进去就行了。
 很明显,这种情况下每个数没进行一次操作,至少减少一个约数的位置,所以这部分时 
     
      
       
       
         O 
        
        
        
          ( 
         
        
          n 
         
        
          d 
         
        
          ) 
         
        
       
      
        O\left(nd\right) 
       
      
    O(nd)的, 
     
      
       
       
         d 
        
       
      
        d 
       
      
    d表示原数的约数个数。
总时间复杂度 O ( n ( d + log  2 n ) + m l o g n ) O\left(n(d+\log^2\,n)+mlog\,n\right) O(n(d+log2n)+mlogn)。
源码
#include<bits/stdc++.h> 
using namespace std;
#define MAXM 500005
#define MAXN 100005
#define MAXT 20000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int lim=500000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,root[MAXM],val[MAXN],sta[MAXN],stak,tim;LL tr[MAXN];
vector<int>vec[MAXM];
void insert(int pos,int aw){while(pos<=n)tr[pos]+=1ll*aw,pos+=lowbit(pos);}
LL query(int pos){LL res=0;while(pos)res+=tr[pos],pos-=lowbit(pos);return res;}
struct ming{
	int lson,rson,val,siz,rnd;
	ming(){lson=rson=val=siz=rnd=0;}
};
class FHQ_Treap{
	private:
		ming tr[MAXT];int tot;
		int newnode(int w){
			int rt=++tot;tr[rt].siz=1;tr[rt].val=w;
			tr[rt].rnd=rand();return rt;
		}
		void pushup(int rt){tr[rt].siz=tr[tr[rt].lson].siz+tr[tr[rt].rson].siz+1;}
		void split(int now,int k,int &x,int &y){
			if(!now){x=y=0;return ;}
			if(tr[now].val>k)
				y=now,split(tr[now].lson,k,x,tr[now].lson),pushup(y);
			else x=now,split(tr[now].rson,k,tr[now].rson,y),pushup(x);
		}
		int merge(int x,int y){
			if(!x||!y)return x+y;
			if(tr[x].rnd<tr[y].rnd){
				tr[x].rson=merge(tr[x].rson,y);
				pushup(x);return x;
			}
			tr[y].lson=merge(x,tr[y].lson);
			pushup(y);return y;
		}
		void search(int rt){
			if(tr[rt].lson)search(tr[rt].lson);
			sta[++stak]=tr[rt].val;
			if(tr[rt].rson)search(tr[rt].rson);
		}
	public:
		int build(int l,int r){
			int mid=l+r>>1,rt=newnode(sta[mid]);
			if(l<mid)tr[rt].lson=build(l,mid-1);
			if(r>mid)tr[rt].rson=build(mid+1,r);
			pushup(mid);return rt;
		}
		void modify(int l,int r,int aw){
			if(aw<2||!root[aw])return ;int x1,y1,x2,y2;split(root[aw],r,x1,y1);
			split(x1,l-1,x2,y2);if(!y2){root[aw]=merge(x2,y1);return ;}
			stak=0;search(y2);int tt=0;
			for(int i=1;i<=stak;i++)if(val[sta[i]]%aw==0){
				insert(sta[i],-val[sta[i]]),
				val[sta[i]]/=aw,insert(sta[i],val[sta[i]]);
				if(val[sta[i]]%aw==0)sta[++tt]=sta[i];	
			}
			if(tt)root[aw]=merge(x2,merge(build(1,tt),y1));
			else root[aw]=merge(x2,y1);
		}
}T;
signed main(){
	read(n);read(m);
	for(int i=1;i<=n;i++){
		read(val[i]),insert(i,val[i]);
		for(int j=2;1ll*j*j<=val[i];j++){
			if(val[i]%j)continue;vec[j].pb(i);
			if(val[i]/j!=j)vec[val[i]/j].pb(i);
		}
		vec[val[i]].pb(i);
	}
	for(int i=2;i<=lim;i++){
		stak=0;for(int j=0;j<vec[i].size();j++)sta[++stak]=vec[i][j];
		if(!stak)continue;root[i]=T.build(1,stak);
	}
	for(int i=1;i<=m;i++){
		int opt,l,r,x;read(opt);tim=i;
		if(opt==1)read(l),read(r),read(x),T.modify(l,r,x);
		if(opt==2)read(l),read(r),printf("%lld\n",query(r)-query(l-1));
	}
	return 0;
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号