• CF1493D GCD of an Array 题解


    Problem

    给出一个长度为 (nleq2 imes10^5) 的序列( 每个数 (leq 2 imes10^5) ) , 维护以下操作:

    1. 单点乘
    2. 全局 Gcd (对 (10^9+7) 取模)

    Sol

    考虑线段树维护。

    首先将每个数质因数分解,每个节点维护每个质因子在每个数中出现最小次数,用 map 存起来即可。

    对于更新,我们只要考虑有修改的质因子出现最小次数是否增加就行了。

    但是会 TLE on test 7 。

    新增优化:

    1. 如果在线段树底层某个质因子出现最小次数没有增加,那么一定不会在上层有改变,舍弃
      2. 预处理每个数分解的结果

    Code

    #define in read()
    #define fi first
    #define se second
    #define pb push_back
    #define vec vector<int>
    #define pii pair<int,int>
    #define vep vector<pii>
    #define umap map<int,int>
    
    typedef long long ll;
    
    int read(){int x = 0,sgn = 1;char ch = getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')sgn=-1;for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);return x*sgn;}
    
    const int N = 2e5+10;
    const int mod = 1e9+7;
    
    int pnum,prime[N],n,a[N],q,id[N];
    bool v[N];
    ll ans = 1;
    vep s[N];
    
    struct node{umap v;}t[N<<2];
    umap :: iterator it;
    
    void shai(){
        for(int i = 2;i < N;i++){
    		if(!v[i]) prime[++pnum] = i,id[i] = pnum;
    		for(int j = 1,x;j <= pnum && prime[j] * i < N;j++){
    	    	v[x = prime[j] * i] = 1;
    	    	if(i % prime[j] == 0) break;
    		}
        }
    }
    
    inline vep divide(int x){
        vep t;
        if(!v[x]) {
    		t.pb(pii(id[x],1));
    		return t;
        }
        
        for(int i = 1;i <= pnum && x > 1;i++){
    		if(x % prime[i] == 0){
    	    	pii res = pii(i,0);
    	    	while(x % prime[i] == 0) res.se++,x /= prime[i];
    	    	t.pb(res);
    	    	if(x == 1) break;
    	    	if(!v[x]) {
    				t.pb(pii(id[x],1));
    				break;
    	    	}
    		}
        }return t;
    }
    
    void build(int o = 1,int l = 1,int r = n){
        if(l == r){
    		vep pp = s[a[l]];
    		for(pii x : pp) t[o].v[x.fi] += x.se;
    		return;
        }
        int mid = l+r>>1;
        build(o<<1,l,mid); build(o<<1|1,mid+1,r);
        for(pii d : t[o<<1].v)	t[o].v[d.fi] = min(d.se,t[o<<1|1].v[d.fi]);
    }
    
    void update(int pos,vep &v,int o = 1,int l = 1,int r = n){
        if(l == r){
    		for(pii x : v) t[o].v[x.fi] += x.se;
    		return;
        }
        int mid = l+r>>1;
        if(pos <= mid) update(pos,v,o<<1,l,mid);
        else if(pos > mid) update(pos,v,o<<1|1,mid+1,r);
        vep lef;
        for(pii x : v)
    	if(min(t[o<<1].v[x.fi],t[o<<1|1].v[x.fi]) > t[o].v[x.fi]) t[o].v[x.fi] = min(t[o<<1].v[x.fi],t[o<<1|1].v[x.fi]),lef.pb(x);
        v = lef;
    }
    
    ll qp(ll x,int t){ll res=1;for(;t;t>>=1,x=x*x%mod)if(t&1)res=res*x%mod;return res;}
    
    int main(){
        shai();
        for(int i = 2;i < N;i++) s[i] = divide(i);
        n = in,q = in;
        for(int i = 1;i <= n;i++) a[i] = in;
        build(); for(pii x:t[1].v) if(x.se >= 1) ans = ans * qp(prime[x.fi],x.se) % mod;
        for(int i = 1;i <= q;i++){
            int pos = in,x = in;
            if(x != 1) {
                vep tmp = s[x],tt = tmp;
                for(pii &y : tt) y.se = t[1].v[y.fi];
                update(pos,tmp);
                for(pii &y : tt)
                    if(t[1].v[y.fi] > y.se) ans = qp(prime[y.fi],t[1].v[y.fi]-y.se) * ans % mod;
            }		
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    
    本博客作者:Werner_Yin(https://www.cnblogs.com/werner-yin/) ,转载时请注明出处,谢谢支持!
  • 相关阅读:
    微信支付-我遇到的那些问题
    [工作笔记]JDK版本不同导致的SSL异常
    mysql与oracle在groupby语句上的细节差异
    微信js-sdk调用
    循序渐进看Java web日志跟踪(3)-Log4J的使用和配置
    循序渐进看Java web日志跟踪(2)-Java日志API认识
    循序渐进看Java web日志跟踪(1)-Tomcat 日志追踪与配置
    手机号码正则表达式(含虚拟运营商)
    网站URL重写(Java UrlRewrite 的使用)
    TCP/IP提供网络传输速率
  • 原文地址:https://www.cnblogs.com/werner-yin/p/solution-cf-1493D.html
Copyright © 2020-2023  润新知