TIOJ-1282

愛蜜利雅的作業2

https://tioj.ck.tp.edu.tw/problems/1282

Description

給定一個長度$n$的正整數序列,有$q$次操作,每次操作可能會對區間$[l,r]$加上$k$或詢問區間$[l,r]$的最大公因數
$1 \leq n,q \leq 10^5$

Solution

想法是利用區間加值等於對差分的兩個單點修改
然後有一個性質是 $\gcd(a,b) = \gcd(a-b,b)$
所以$[l,r]$區間的GCD會等於$\gcd(\gcd(a _ {l+1}-a_l, a _ {l+2}-a _ {l+1}, \dots, a_r-a _ {r-1}), a_r)$之類的
求$a_r$可以用BIT就好,前面那項我則是用線段樹維護
複雜度$\mathcal{O}(n\log c + q\log n \log c)$

注意算完GCD要加絕對值,因為差分會出現負數,此時__gcd可能回傳負數

AC code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//   __________________
//  | ________________ |
//  ||          ____  ||
//  ||   /\    |      ||
//  ||  /__\   |      ||
//  || /    \  |____  ||
//  ||________________||
//  |__________________|
//  \###################\
//   \###################\
//    \        ____       \
//     \_______\___\_______\
// An AC a day keeps the doctor away.

#pragma g++ optimize("Ofast")
#pragma loop_opt(on)
#include <bits/extc++.h>
#ifdef local
#define debug(x) (cerr<<#x<<" = "<<(x)<<'\n')
#else
#define debug(x) ((void)0)
#endif // local

using namespace std;
typedef int64_t ll;
constexpr ll N = 100025, INF = 1e18, MOD = 1000000007, K = 256, inf = 1e9;

struct FenwickTree{
    ll sum[N],n;
    void init(ll v[],int _n) {
        n = _n;
        for(int i = 1; i <= n; i++) sum[i] = v[i] - v[i-(i&-i)];
    }
    ll query(int p) {
        ll res = 0;
        for(; p; p-=p&-p) res += sum[p];
        return res;
    }
    void edit(int p,ll d) {
        for(; p<=n; p+=p&-p) sum[p] += d;
    }
} BIT;
struct SegmentTree {
    ll seg[N<<1],n;
    void init(ll v[],int _n) {
        n = _n;
        for(int i = 0; i < n; i++) seg[i+n] = v[i];
        for(int i = n-1; i > 0; i--) seg[i] = __gcd(seg[i<<1],seg[i<<1|1]);
    }
    ll query(int l,int r) {
        ll res = 0;
        for(l+=n,r+=n; l<r; l>>=1,r>>=1) {
            if(l&1) res = __gcd(res,seg[l++]);
            if(r&1) res = __gcd(res,seg[--r]);
        }
        return abs(res);
    }
    void edit(int p,ll d) {
        for(seg[p+=n]+=d; p>1; p>>=1) seg[p>>1] = __gcd(seg[p],seg[p^1]);
    }
} sgt;

int n,q;
ll v[N];
signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0);
    cin >> n >> q;
    for(int i = 1; i <= n; i++) cin >> v[i];
    BIT.init(v,n);
    for(int i = 0; i < n; i++) v[i] = v[i+1]-v[i];
    sgt.init(v,n);
    while(q--) {
        int tp,l,r;
        ll k;
        cin >> tp;
        if(tp == 1) {
            cin >> l >> r >> k;
            BIT.edit(l,k);
            BIT.edit(r+1,-k);
            sgt.edit(l-1,k);
            sgt.edit(r,-k);
        }else {
            cin >> l >> r;
            cout << abs(__gcd(BIT.query(r), sgt.query(l,r))) << '\n';
        }
    }
}

註: 寫題解的時候一直TLE,後來發現是我的edit宣告成ll卻沒回傳東西orz…
似乎在TIOJ上宣告成非void的函數而不回傳值有機會出問題…

comments powered by Disqus