Codeforces Round #705 (Div. 2) D_Codeforces Round
题解:
刚拿到这个题目的时候我就想,就线段树维护区间gcd,这不就成了吗,tree[rt].gcd = gcd(tree[lson].gcd, tree[rson].gcd) ,又是单点修改,连lazy标记都不用,然后我又仔细想了想发现不对劲,因为gcd对模没有和加减一样类似的性质,也就是说。。。我的以上思路不对。。。。(cf网站中一些大佬给出了AC了的线段树代码,暂时还没研究) 看了一下官方题解,以下是对官方题解的部分翻译以及自己的一些理解,(官方题解全英文)
主导思想是质因数分解!因为我们发现不管是最开始的n个数还是之后的修改,其中的操作数都是2e5范围内的数,这对我们就有一个暗示(赛时也往这方面想了的,不过还是对数论的学习不够到位),我们可以打一个素数表,这个素数表divs表示2e5以内的每个数的最小素因子,i.e.divs[x]表示x的最小素因子,这个可以随便找一个筛法就可,官方题解给的是优化了的埃氏筛法,时间复杂度是o(nloglogn),我下面给的是时间复杂度稍微更小一点的欧拉筛o(n),当然更优秀的筛法也有e.g.杜教筛啥的,不过对于此题没必要,埃氏筛法就可。然后就是维护n个数每个数的质因子以及指数,其中题目数据范围1<=n<=2e5,但是由于每个数的质因子数目以及种类可能各异,简单的用二维数组维护可能会MLE,因此可以将第二维离散化,即用一个map映射来维护;又由于质因数分解后求gcd就是求n个数每个质因数的最小指数,因此可以用pcnt[x]来维护n个数的x质因子中的指数(由于不管是初始n个数还是之后的乘法操作数都是2e5以内的,所以开比2e5大一点的空间即可),官方题解用到了multiset来存,即pcnt为multiset数组。
每个询问的时间复杂度为log级别(官方题解的叙述"Each query is processed in the complexity of the amount of prime divisors multiplied by the time of map and multiset operation, i.e. log.")
我的代码如下(很大程度模仿官方):

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define IOS std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
typedef long long ll;
typedef unsigned long long ull;
struct InputOutputStream {
    enum { SIZE = 1000001 };
    char ibuf[SIZE], *s, *t, obuf[SIZE], *oh;
    bool eof;
 
    InputOutputStream() : s(), t(), oh(obuf), eof(false) {}
    ~InputOutputStream() { fwrite(obuf, 1, oh - obuf, stdout); }
 
    explicit operator bool() const {
        return static_cast<bool>(eof == false);
    }
 
    inline char read() {
        if (s == t) t = (s = ibuf) + fread(ibuf, 1, SIZE, stdin);
        return s == t ? -1 : *s++;
    }
 
    inline InputOutputStream &operator>>(char* x) {
        static char c;
        for (c = read(); isspace(c); c = read())
            if (c == -1) {eof = true; return *this;}
        for (; !isspace(c); c = read()) *x = c, ++x;
        *x = 0;
        return *this;
    }
 
    template <typename T>
    inline InputOutputStream &operator>>(T &x) {
        static char c;
        static bool iosig;
        for (c = read(), iosig = false; !isdigit(c); c = read()) {
            if (c == -1) {eof = true; return *this;}
            iosig |= c == '-';
        }
        for (x = 0; isdigit(c); c = read()) x = x * 10 + (c ^ '0');
        if (iosig) x = -x;
        return *this;
    }
 
    inline void print(char c) {
        if (oh == obuf + SIZE) {
            fwrite(obuf, 1, SIZE, stdout);
            oh = obuf;
        }
        *oh++ = c;
    }
 
    template <typename T>
    inline void print(T x) {
        static int buf[23], cnt;
        if (x != 0) {
            if (x < 0) print('-'), x = -x;
            for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
            while (cnt) print((char)buf[cnt--]);
        } else print('0');
    }
 
    template <typename T>
    inline InputOutputStream &operator<<(const T &x) {
        print(x);
        return *this;
    }
 
    inline void print(const char* x) {
        for(; *x; x++)
            print(*x);
    }

    inline void print(char* x) {
        for(; *x; x++)
            print(*x);
    }    
} io;

const int mod = 1e9 + 7;
const int maxn = 2e5 + 50;
const int max_val = 2e5 + 50;

int prime[max_val], id = 0; 
int divs[max_val];   

void euler() {
    memset(divs, 0, sizeof(divs));
    divs[1] = 1;
    for(int i = 2;i <= 200000;++i) {
        if(divs[i] == 0) {
            prime[++id] = i;
            divs[i] = i;
        } 
        for(int j = 1;j <= id && i * prime[j] <= 200000;++j) {
            divs[i*prime[j]] = prime[j];
            if(i % prime[j] == 0) {
                break;
            }
        }
    }
}

int n, q;
ll ans = 1;
multiset<int> pcnt[max_val];
map<int, int> cnt_divs[maxn];

void modify(int x, int val) {
    while(val != 1) {
        int div = divs[val], k = 0;
        while(divs[val] == div) { k++; val /= div; }
        int lst_cnt = cnt_divs[x][div];
        int lst_min = 0;
        if((int)pcnt[div].size() == n) {
            lst_min = *(pcnt[div].begin());
        }
        if(lst_cnt != 0) {
            pcnt[div].erase(pcnt[div].find(lst_cnt));
        }
        cnt_divs[x][div] += k;
        pcnt[div].emplace(cnt_divs[x][div]);
        if((int)pcnt[div].size() == n) {
            for(int i = lst_min + 1;i <= (*pcnt[div].begin());++i) {
                ans = ans * div % mod;
            }
        }
    }
}

signed main() {	
    io >> n >> q;
    
    euler();

    for(int i = 1;i <= n;++i) {
        int val;
        io >> val;
        modify(i, val);
    }

    while(q--) {
        int x, val;
        io >> x >> val;
        modify(x, val);
        io << ans << '\n';
    }
    return 0;
}