1. 程式人生 > >清華集訓2014 奇數國

清華集訓2014 奇數國

  • 【清華集訓2014】奇數國
  • 尤拉函式+線段樹,傻逼題……。
  • 首先那個\(ax+by=1\)就是在搞笑,想一想有整數的條件就是\(gcd(a,b)=1\),實際上是讓你求\(\phi\)
  • 所以現在需要支援兩種操作,區間積求\(phi\),單點修改。
  • 因為每個數都只有最多\(60\)個不同質因子,所以可以把它分解質因數。
  • 然後就能用\(60\)個線段樹來維護每個質因子個數。
  • 詢問是求區間乘積的尤拉函式,然後用公式\(\phi_n=n*\prod(1-\frac {1}{p_i})\)就可以了。
  • 複雜度\(O(60*qlogn)\)
  • 線段樹可以換成樹狀陣列,常數小很多。
#include<bits/stdc++.h>
#define R register int
#define db double
#define ll long long 
using namespace std;
const int N=100001;
const int mod=19961993;
int n,m,op,u,v,ans;
int gi(){
    R x=0,k=1;char c=getchar();
    while(c!='-'&&(c<'0'||c>'9'))c=getchar();
    if(c=='-')k=-1,c=getchar();
    while(c<='9'&&c>='0')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*k;
}
namespace cpp1{
    int tot,mk[N],prm[N];
    struct mon{
        int s[61];
        void init(){memset(s,0,sizeof(s));}
    }te[N*4],nw;
    int Qpow(R x,R y){
        R ans=1,bas=x;
        while(y){
            if(y&1)ans=1ll*ans*bas%mod;
            bas=1ll*bas*bas%mod,y>>=1;
        }return ans;
    }
    mon mul(mon x,mon y){
        mon z;
        for(R i=1;i<=60;++i)z.s[i]=x.s[i]+y.s[i];
        return z;
    }
    mon rev(R x){
        mon z;z.init();
        for(R j=1;j<=tot;++j){
            while(x%prm[j]==0)
                z.s[j]++,x/=prm[j];
        }
        return z;
    }
    void init(){
        mk[0]=mk[1]=1;
        for(R i=2;i<N;++i){
            if(!mk[i])prm[++tot]=i;
            for(R j=1;j<=tot&&i*prm[j]<N;++j){
                mk[i*prm[j]]=1;
                if(i%prm[j]==0)break;
            }
        }tot=60;
    }
    void upd(R Le,R Ri,R ps,R i){
        if(Le==Ri){te[i]=nw;return ;}
        R mid=(Le+Ri)>>1,ls=(i<<1),rs=(ls|1);
        if(ps<=mid)upd(Le,mid,ps,ls);else upd(mid+1,Ri,ps,rs);
        te[i]=mul(te[ls],te[rs]);
    }
    mon query(R Le,R Ri,R le,R ri,R i){
        if(Le==le&&Ri==ri)return te[i];
        R mid=(Le+Ri)>>1,ls=(i<<1),rs=(ls|1);
        if(ri<=mid)return query(Le,mid,le,ri,ls);
        else if(le>mid)return query(mid+1,Ri,le,ri,rs);
        else return mul(query(Le,mid,le,mid,ls),query(mid+1,Ri,mid+1,ri,rs));
    }
    void Main(){
        n=100000,m=gi(),init(),nw.init(),nw.s[2]=1;
        for(R i=1;i<=n;++i)upd(1,n,i,1);
        while(m--){
            op=gi(),u=gi(),v=gi();
            if(op==1)nw=rev(v),upd(1,n,u,1);
            else {
                nw=query(1,n,u,v,1),ans=1;
                for(R j=1;j<=60;++j)
                    if(nw.s[j]){
                        ans=1ll*ans*(prm[j]-1)%mod;
                        ans=1ll*ans*Qpow(prm[j],nw.s[j]-1)%mod;
                    }
                printf("%d\n",ans);
            }
        }
    }
}
int main(){
    cpp1::Main();
    return 0;
}