1. 程式人生 > >尤拉函式 線段樹 狀壓 奇數國

尤拉函式 線段樹 狀壓 奇數國

讓我們一起來%forever_shi神犇

題意:求區間積的 ϕ \phi 值。

題解:
n u m b e

r x + p r o d u c t
y = 1 number∗x+product∗y=1 可以轉化為 g c d
( n u m b e r , p r o d u c t ) = 1 gcd(number,product)=1
,即求 ϕ ( p r o d u c t ) \phi(product)
題目保證所有的數都可以表示成前60個質數的若干次方的形式,根據尤拉函式的性質,我們只需要維護區間的product和區間內出現了哪些質因數,product維護區間乘積很好做,但是維護60個質因數的話開60個變數可能可以,但是有可能被卡空間,這裡其實可以用一個ll來狀壓每個質數是否出現了。然後就是線段樹了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=19961993;
int m,num;
ll p[1000];
ll inv[1000];
struct node
{
    int l,r;
    ll mul,p;
}tr[1001000],ans;
ll ksm(ll q,ll w)
{
    ll h=1;
    while(w)
    {
        if(w&1)
            h=h*q%mod;
        q=q*q%mod;
        w>>=1;
    }
    return h;
}
void pushdown(int rt)
{
    tr[rt].mul=(tr[rt*2].mul%mod*tr[rt*2+1].mul%mod)%mod;
    tr[rt].p=tr[rt*2].p|tr[rt*2+1].p; 
} 
void build(int rt,int l,int r)
{
    tr[rt].l=l;
    tr[rt].r=r;
    if(l==r)
    {
        tr[rt].mul=3;
        tr[rt].p=2;
        return;
    }
    int mid=(l+r)/2;
    build(rt*2,l,mid);
    build(rt*2+1,mid+1,r);
    pushdown(rt);
}
void update(int rt,int x,int y)
{
    int l=tr[rt].l;
    int r=tr[rt].r;
    if(l==r)
    {
        ll now=0;
        for(ll i=1;i<=60;++i)
            if(y%p[i]==0)
                 now+=(1LL<<(i-1));
        tr[rt].p=now;
        tr[rt].mul=y;
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid)
        update(rt*2,x,y);
    else
        update(rt*2+1,x,y);
    pushdown(rt);
}
void query(int rt,int L,int R)
{
    int l=tr[rt].l;
    int r=tr[rt].r;
    if(l>=L&&r<=R)
    {
        ans.mul=(ans.mul%mod*tr[rt].mul%mod)%mod;
        ans.p|=tr[rt].p;
        return;
    }	
    int mid=(l+r)/2;
    if(L<=mid)
        query(rt*2,L,R);
    if(R>=mid+1)
        query(rt*2+1,L,R);
}
int main()
{
    scanf("%d",&m);
    for(int i=2;i<=300;++i)
    {
        int sum=0;
        for(int j=1;j<=i;++j)
            if(i%j==0)
                sum++;
        if(sum<=2)
            p[++num]=i;
        if(num==60)
            break;
    }
    for(int i=1;i<=60;++i)
        inv[i]=ksm(p[i],mod-2);
    build(1,1,100000);
    for(int i=1;i<=m;++i)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==0)
        {
            ans.mul=1;
            ans.p=0;
            query(1,y,z);
            ll res=ans.mul;
            for(int j=1;j<=60;++j)
                if(ans.p&(1LL<<(j-1)))
                    res=(res%mod*(p[j]-1)%mod*inv[j]%mod)%mod;
            printf("%lld\n",res);
        }
        else 
            update(1,y,z);
    }
    return 0;
}