​题目链接​

题目大意: 给出你n个数,m次操作,让你求操作后n个数的gcd


思路: 因为我们要求gcd。很容易想到我们需要唯一分解这n个数,找到他们公共的部分,乘积就是要求的gcd,重点难点是我们每次要添加更新一个数的因子,所以公共部分可能会改变,也可能不改变。 这就需要我们维护,这个公共部分,我们先把公共部分提取出来做贡献,然后判断加入之后是否构成一个n个数都有的部分,所以我们需要维护一个含插入,删除最小值的数据结构。我就想到这个地方,看被人的博客用的都是​​multiset​​。感兴趣的可以去学一下,其实还挺好的。

简单的说下过程:首先对每个数进行唯一分解,分解出来的数让他找到对应的贡献,(就是进入insert)

  1. 如果这个数原本数就有,那么需要更新这个数(如果前面乘过这个最小贡献就需要把这个除下来转化成逆元),更新这个数,如果n个数都有更新。
  2. 如果这个数原本没有,那么直接更新就行,直接判断是否n个数都有,都有这做出贡献乘上即可。
#include <set>
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define
#define
#define
#define
#define
#define
const int maxn=2e5+10;
#define
#define
#define
const int mod=1e9+7;
const int MOD=1e9+7;

inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
ll n,m,d;
ll a[maxn];
multiset<ll> s[maxn];
map<ll,ll> mp[maxn];
ll qpow(ll a,ll b) {
ll ans=1;
while(b) {
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
ll inv(ll x) {
return qpow(x,mod-2);
}

void insert(ll k, ll i,ll cnt) {
if(mp[k].count(i)) {
if(s[i].size()==n) d=d*inv(qpow(i,*s[i].begin()))%mod;
s[i].erase(s[i].find(mp[k][i]));
mp[k][i]=mp[k][i]+cnt;
s[i].insert(mp[k][i]);
if(s[i].size()==n) d=d*qpow(i,*s[i].begin())%mod;
} else {
mp[k][i]=cnt;
s[i].insert(mp[k][i]);
if(s[i].size()==n) d=d*qpow(i,*s[i].begin())%mod;
}
}
void divide(ll k,ll x) {
for(int i=2; i<=x/i; i++) {
if(x%i==0) {
ll cnt=0;
while(x%i==0) {
x=x/i;
cnt++;
}
insert(k,i,cnt);
}
}
if(x>1)insert(k,x,1);
}

int main() {
scanf("%lld%lld",&n,&m);
d=1;
for(int i=1; i<=n; i++) {
scanf("%lld",&a[i]);
}
for(int i=1; i<=n; i++) {
divide(i,a[i]);
}


while(m--) {
ll i,x;
scanf("%lld%lld",&i,&x);
divide(i,x);
printf("%lld\n",d);
}
return 0;
}