1. 程式人生 > >[BZOJ3813] 奇數國 - 線段樹

[BZOJ3813] 奇數國 - 線段樹

歐拉函數 tput return gist pri 乘法 線段 tps number

3813: 奇數國

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 912 Solved: 508
[Submit][Status][Discuss]

Description

在一片美麗的大陸上有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取模後的答案。

Input

第一行一個整數x表示領袖清點和變動存款的總次數。 接下來x行,每行3個整數ai,bi,ci。ai為0時表示該條記錄是清點計劃,領袖會清點bi到ci的銀行存款,你需要對該條記錄計算出GFS想要的答案。ai為1時表示該條記錄是存款變動,你要把銀行bi的存款改為ci,不需要對該記錄進行計算。

Output

輸出若幹行,每行一個數,表示那些年的答案。

Sample Input

6
013
115
013
117
013
023

Sample Output

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個數。

HINT

x≤100000,當ai=0時0≤ci−bi≤100000


題解:

用線段樹維護區間乘積,並且用一個longlong類型變量表示這個區間有沒有選擇某一個質數;

合並的時候乘積就直接乘起來, 狀態直接把左兒子右兒子的狀態取或;

計算的時候直接按照歐拉函數的數學公式算


Code:

#include <iostream>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define ll long long
#define mod 19961993
int TI;

int ps[66] = {0,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};
int inv[300];

struct Segment
{
    ll sum;
    ll bit;
    Segment() {sum = 1, bit = 0;}
}t[400009], ans;
#define ls(o) o << 1
#define rs(o) o << 1 | 1
#define sum(o) t[o].sum
#define bit(o) t[o].bit

inline void update(int o){sum(o)=sum(ls(o))*sum(rs(o))%mod;bit(o)=(bit(ls(o))|bit(rs(o)));}

inline void build(int o, int l, int r)
{
    if (l == r)
    {
        sum(o) = 3;
        bit(o) = 2;
        return ;
    }
    int mid = l + r >> 1;
    build(o<<1, l, mid);
    build(o<<1|1, mid + 1, r);
    sum(o)=sum(ls(o))*sum(rs(o))%mod;
    bit(o) = 2;
}

inline void change(int l,int r, int o, int now, int der)
{
    if (l == r)
    {
        sum(now) = der;
        ll p = 0;
        for (register int i = 1 ; i <= 60 ; i ++)
            if (der % ps[i] == 0) p |= 1LL<<(i-1);
        bit(now) = p;
        return ;
    }
    int mid = l + r >> 1;
    if (o <= mid) change(l, mid, o, ls(now), der);
    else change(mid + 1, r, o, rs(now), der);
    sum(now) = sum(ls(now)) * sum(rs(now)) % mod;
    bit(now) = bit(ls(now)) | bit(rs(now));
}

inline void query(int l, int r, int lq, int rq, int o)
{
    if (l >= lq and r <= rq)
    {
        ans.sum = (ans.sum * sum(o)) % mod;
        ans.bit |= bit(o);
        return;
    }
    int mid = l + r >> 1;
    if (lq <= mid) query(l, mid, lq, rq, ls(o));
    if (rq > mid) query(mid + 1, r, lq, rq, rs(o));    
}


int main()
{
    scanf("%d", &TI);
    inv[1] = 1;
    for (register int i = 2 ; i <= 281 ; i ++) 
        inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
    int n = 100000;
    build(1, 1, n);
    for (register int i = 1 ; i <= TI ; i ++)
    {
        int opt, x, y;
        scanf("%1d%1d%1d", &opt, &x, &y);
        if (opt == 0)
        {
            ans.sum = 1, ans.bit = 0;
            query(1, n, x, y, 1);
            ll res = ans.sum;
            for (register int j = 1 ; j <= 60 ; j ++)
            {
                if (ans.bit & (1LL<<(j-1)))
                {
                    res = (res * (ps[j] - 1)) % mod;
                    res = (res * inv[ps[j]]) % mod;
                }
            }
            printf("%d\n", (int)res);
        }
        else
        {
            change(1, n, x, 1, y);
        }
    }
    return 0;
}

[BZOJ3813] 奇數國 - 線段樹