zoukankan      html  css  js  c++  java
  • 线段树+欧拉函数——cf1114F

    调了半天,写线段树老是写炸

    /*
    两个操作
    1.区间乘法
    2.区间乘积询问欧拉函数 
    
    欧拉函数计算公式
        phi(mul(ai))=mul(ai) * (p1-1)/p1 * (p2-1)/p2 * .. * (pk-1)/pk
    因为只有300以内的质数(62个)用一个long long来状态压缩
    因此线段树结点维护住区间的质数状态集合S,区间的乘积
    
    操作1 [l,r] x:把x质因数分解,然后更新S,然后再更新乘积,
    操作2 [l,r]:询问到区间的状态集合S,区间的乘积,再求逆元进行除法
    
    先把62个质数的逆元求出来 

    线段树结点维护区间乘积,区间质数集合S,然后两个lazy标记
    */ #include<bits/stdc++.h> using namespace std; #define ll long long #define mod 1000000007 #define maxn 400005 ll n,q; ll p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157, 163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293}; ll invp[100]; ll Pow(ll a,ll b){ ll res=1; while(b){ if(b%2)res=res*a%mod; b>>=1;a=a*a%mod; } return res; } ll a[maxn]; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 //mul是区间乘积,l_mul是区间乘的lazy ll msk[maxn<<2],mul[maxn<<2],l_msk[maxn<<2],l_m[maxn<<2]; inline ll calc(ll x){ ll res=0; for(ll i=0;i<62;i++) if(x%p[i]==0) res|=((ll)1<<i); return res; } void pushup(int rt){ mul[rt]=mul[rt<<1] * mul[rt<<1|1] % mod; msk[rt]=msk[rt<<1] | msk[rt<<1|1]; } void pushdown(int l,int r,int rt){ if(l_msk[rt]!=0){ l_msk[rt<<1] |= l_msk[rt]; msk[rt<<1] |= l_msk[rt]; l_msk[rt<<1|1] |= l_msk[rt]; msk[rt<<1|1] |= l_msk[rt]; l_msk[rt]=0; } if(l_m[rt]!=1){//整个区间都要乘 int m=l+r>>1; l_m[rt<<1]=l_m[rt<<1] * l_m[rt]%mod; mul[rt<<1]=Pow(l_m[rt],m-l+1) * mul[rt<<1]%mod; l_m[rt<<1|1]=l_m[rt<<1|1] * l_m[rt]%mod; mul[rt<<1|1]=Pow(l_m[rt],r-m) * mul[rt<<1|1]%mod; l_m[rt]=1; } } void build(int l,int r,int rt){ l_msk[rt]=0;l_m[rt]=1; if(l==r){ mul[rt]=a[l]; msk[rt]=calc(a[l]); return ; } int m=l+r>>1; build(lson);build(rson); pushup(rt); } void up_mul(int L,int R,ll x,int l,int r,int rt){ if(L<=l && R>=r){ l_m[rt]=l_m[rt]*x%mod; mul[rt]=mul[rt]*Pow(x,r-l+1)%mod; return; } pushdown(l,r,rt); int m=l+r>>1; if(L<=m)up_mul(L,R,x,lson); if(R>m)up_mul(L,R,x,rson); pushup(rt); } void up_S(int L,int R,ll S,int l,int r,int rt){ if(L<=l && R>=r){ l_msk[rt]|=S; msk[rt]|=S; return; } pushdown(l,r,rt); int m=l+r>>1; if(L<=m) up_S(L,R,S,lson); if(R>m) up_S(L,R,S,rson); pushup(rt); } ll q_mul(int L,int R,int l,int r,int rt){ if(L<=l && R>=r)return mul[rt]; pushdown(l,r,rt); int m=l+r>>1; ll res=1; if(L<=m) res=res*q_mul(L,R,lson)%mod; if(R>m) res=res*q_mul(L,R,rson)%mod; return res; } ll q_S(int L,int R,int l,int r,int rt){ if(L<=l && R>=r)return msk[rt]; pushdown(l,r,rt); int m=l+r>>1; ll S=0; if(L<=m) S|=q_S(L,R,lson); if(R>m) S|=q_S(L,R,rson); return S; } int main(){ for(int i=0;i<62;i++) invp[i]=Pow(p[i],mod-2); cin>>n>>q; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); build(1,n,1); char op[100];ll l,r,x; while(q--){ scanf("%s",op); if(op[0]=='M'){ scanf("%lld%lld%lld",&l,&r,&x); up_mul(l,r,x,1,n,1); ll S=calc(x); up_S(l,r,S,1,n,1); } else { scanf("%lld%lld",&l,&r); ll S=q_S(l,r,1,n,1); ll mul=q_mul(l,r,1,n,1); for(ll i=0;i<62;i++) if(S & ((ll)1<<i)) mul=(mul*invp[i]%mod*(p[i]-1)%mod); cout<<mul<<endl; } } return 0; }
  • 相关阅读:
    ZMQ面面观
    windows10系统右键新建菜单的自定义
    元组,列表,字典前加*
    HTTP状态码(转)
    字符串利用%02d将月份前加0
    python中while与else的联姻
    sys.argv
    pandas的read_csv踩到的坑
    wireshark抓包总结
    bcolz
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10906811.html
Copyright © 2011-2022 走看看