歐拉函數+線段樹 奇數國

問題 B: 奇數國
時間限制: 1 Sec 內存限制: 256 MB
提交: 82 解決: 44
[提交][狀態][討論版]
題目描述
在一片美麗的大陸上有100000個國家,記爲1到100000。這裏經濟發達,有數不盡的賬房,並且每個國家有一個銀行。某大公司的領袖在這100000個銀行開戶時都存了3大洋,他惜財如命,因此會不時地派小弟GFS清點一些銀行的存款或者讓GFS改變某個銀行的存款。該村子在財產上的求和運算等同於我們的乘法運算,也就是說領袖開戶時的存款總和爲3100000。這裏發行的軟妹面額是最小的60個素數(p1=2,p2=3,…,p60=281),任何人的財產都只能由這60個基本面額表示,即設某個人的財產爲fortune(正整數),則fortune=p1^k1*p2^k2*……p60^K60。
領袖習慣將一段編號連續的銀行裏的存款拿到一個賬房去清點,爲了避免GFS串通賬房叛變,所以他不會每次都選擇同一個賬房。GFS跟隨領袖多年已經摸清了門路,知道領袖選擇賬房的方式。如果領袖選擇清點編號在[a,b]內的銀行財產,他會先對[a,b]的財產求和(計爲product),然後在編號屬於[1,product]的賬房中選擇一個去清點存款,檢驗自己計算是否正確同時也檢驗賬房與GFS是否有勾結。GFS發現如果某個賬房的編號number與product相沖,領袖絕對不會選擇這個賬房。怎樣纔算與product不相沖呢?若存在整數x,y使得number*x+product*y=1,那麼我們稱number與product不相沖,即該賬房有可能被領袖相中。當領袖又賺大錢了的時候,他會在某個銀行改變存款,這樣一來相同區間的銀行在不同的時候算出來的product可能是不一樣的,而且領袖不會在某個銀行的存款總數超過1000000。
現在GFS預先知道了領袖的清點存款與變動存款的計劃,想請你告訴他,每次清點存款時領袖有多少個賬房可以供他選擇,當然這個值可能非常大,GFS只想知道對19961993取模後的答案。
輸入
第一行一個整數x表示領袖清點和變動存款的總次數。
接下來x行,每行3個整數ai,bi,ci。ai爲0時表示該條記錄是清點計劃,領袖會清點bi到ci的銀行存款,你需要對該條記錄計算出GFS想要的答案。ai爲1時表示該條記錄是存款變動,你要把銀行bi的存款改爲ci,不需要對該記錄進行計算。
輸出
輸出若干行,每行一個數,表示那些年的答案。
樣例輸入
6
013
115
013
117
013
023
樣例輸出
18
24
36
6

explanation

初始化每個國家存款都爲3;

1到3的product爲27,[1,27]與27不相沖的有18個數;
1的存款變爲5;
1到3的product爲45,[1,45]與45不相沖的有24個數;
1的存款變爲7;
1到3的product爲63,[1,63]與63不相沖的有36個數;
2到3的product爲9,[1,9]與9不相沖的有6個數。
提示
x≤100000,當ai=0時0≤ci−bi≤100000

說白了要求數列某一段乘積的歐拉函數.
根據歐拉定理,φ(n)=n*∏((p-1)/p) (p爲n的質因數)
一棵線段樹維護這一段乘積,並維護這一段有哪些質數。而題目中指出只會用到60個質數,那就很方便了,可以狀壓一下,用二進制記錄下有哪些質數,60剛好不會爆long long.

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mod 19961993
#define N 100000
#define ll long long
using namespace std;
int read()
{
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
    while(x>='0'&&x<='9'){sum=(sum<<3)+(sum<<1)+x-'0';x=getchar();}
    return sum*f;
}
struct tree
{
    int l,r; ll h,sum;
}t[N*4+100];
int m;
ll s1,s2,ans,xp[65],hh[65],pri[65]={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,};
ll cheng(ll x,ll m)
{
    ll ans=1;
    while(m)
    {
        if(m&1)ans=ans*x%mod;
        x=x*x%mod;
        m>>=1;
    }
    return ans;
}
void build(int l,int r,int x)
{
    t[x].l=l;t[x].r=r;
    if(l==r)
    {
        t[x].h=3;t[x].sum=xp[1];
        return;
    }
    int mid=l+r>>1;
    build(l,mid,x*2);
    build(mid+1,r,x*2+1);
    t[x].h=t[x*2].h*t[x*2+1].h%mod;
    t[x].sum=t[x*2].sum|t[x*2+1].sum;
}
void c(int l,int k,int x)
{
    if(t[x].l==t[x].r)
    {
        t[x].h=k;t[x].sum=0;
        for(int i=0;i<60;i++)
            if(k%pri[i]==0)t[x].sum|=xp[i];
        return;
    }
    int mid=t[x].l+t[x].r>>1;
    if(l<=mid)c(l,k,x*2);
    else c(l,k,x*2+1);
    t[x].h=t[x*2].h*t[x*2+1].h%mod;
    t[x].sum=t[x*2].sum|t[x*2+1].sum;
}
void q(int l,int r,int x)
{
    if(t[x].l>=l&&t[x].r<=r)
    {
        s2=s2*t[x].h%mod;
        s1|=t[x].sum;
        return;
    }
    int mid=t[x].l+t[x].r>>1;
    if(l<=mid)q(l,r,x*2);
    if(r>mid)q(l,r,x*2+1);
}
int main()
{
    m=read();
    for(int i=0;i<60;i++)
    {
        hh[i]=cheng(pri[i],mod-2);
        hh[i]=(pri[i]-1)*hh[i]%mod;
    }
    xp[0]=1;for(int i=1;i<=60;i++)xp[i]=xp[i-1]*2LL;
    build(1,N,1);
    int x,a,b;
    while(m--)
    {
        x=read();a=read();b=read();
        if(!x)
        {
            s1=0;ans=s2=1;q(a,b,1);
            for(int i=0;i<60;i++)if(xp[i]&s1)(ans*=hh[i])%=mod;
            printf("%lld\n",ans*s2%mod);
        }
        else c(a,b,1);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章