E.小红的公倍数(set)
区间合并,线性筛预处理每个数的最小质因子和 质数i的次方。
每次对于区间 先分裂包含位置和的区间,然后再合并。
时间复杂度:
#pragma GCC optimize("Ofast","inline")
#pragma GCC optimize(2)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <math.h>
#include <map>
#include <set>
#include <queue>
#include "unordered_map"
using namespace std;
#define endl '\n'
const int maxn = 2e4 + 5;
const int mod = 1e9 + 7;
long long qb[maxn][21];
int a[maxn],n,m,nxt[maxn];
struct node {
int l, r;
unordered_map<int,int> mp;
mutable long long v;
bool operator <(const node &a) const {
return l < a.l;
}
};
set <node> s;
set<node>::iterator split(int pl) {
auto it = --s.upper_bound({pl});
if(it->l == pl) return it;
int l = (*it).l, r = (*it).r,v = (*it).v;
unordered_map<int,int> mp = (*it).mp;
s.erase(it); s.insert((node){l, pl - 1,mp,v});
return s.insert((node){pl, r,mp,v}).first;
}
inline int max(int a,int b){
return a > b ? a : b;
}
//提取区间一定要先分裂右边再分裂左边,不然可能你到到时分裂的后边已经是被删除的,然后就会报错
long long assign(int l, int r) {
auto it = s.upper_bound({l});
it --;
if (it->r >= r){
return it->v;
}
auto itr = split(r + 1), itl = split(l);
auto resl = itl,resr = itr;
unordered_map<int,int> p;
for(auto it = itl;it != itr;it ++){ //这里如果先分裂左边 右边可能是已经是删除的找不到了
for(auto k : it->mp){
p[k.first] = max(k.second,p[k.first]);
}
}
long long x = 1;
for(auto k : p){
x = x * qb[k.first][k.second] % mod;
}
while (itl != s.begin() && prev(itl)->v == x)--itl;
while (itr->v == x)++itr;
int ll = itl->l, rr = itr->l - 1;
s.erase(itl,itr);
s.insert((node){ll,rr,p,x});
return x;
}
void solve(){
cin >> n >> m;
for (int i = 1; i <= maxn - 2; ++i) {
qb[i][0] = 1;
for (int j = 1; j <= 20; ++j) {
qb[i][j] = qb[i][j - 1] * i % mod;
}
}
for (int i = 1; i <= n; ++i) {
cin >> a[i];
unordered_map<int,int> mp;
while (a[i] > 1){
int cur = nxt[a[i]];
int ans = 0;
while (nxt[a[i]] == cur) ans ++,a[i] /= cur;
mp[cur] = ans;
}
s.insert({i,i,mp,a[i]});
}
s.insert({n+1,n+1});
while (m --){
int l,r;
cin >> l >> r;
cout << assign(l,r) << endl;
}
}
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t = 1;
for (int i = 2; i < maxn; ++i) {
if (nxt[i] == 0) {
nxt[i] = i;
qb[i][0] = 1;
for (int j = 1; j <= 20; ++j) qb[i][j] = 1ll * qb[i][j - 1] * i % mod;
if (i > 10000) continue;
for (int j = i * i; j < maxn; j += i) {
if (nxt[j] == 0) nxt[j] = i;
}
}
}
// cin >> t;
while (t--) solve();
}