牛客训练赛100 E(珂朵莉树)
牛客训练赛100 E(珂朵莉树)
题意:
小红拿到了一个数组,她有以下一种操作:
将[l,r]区间所有数变成该区间所有数的lcm,并输出这个lcm。
区间lcm指区间内所有数的最小公倍数。
一共q次操作。
保证数据随机
思路
一眼珂朵莉树,主要是代码常数问题,详见注释
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<string>
#include<random>
#define yes puts("yes");
#define map unordered_map
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e4 ,mod=1e9 + 7;
// 常数优化1: 欧拉筛 能预处理就预处理
int p[MAXN], idx;
bool st[MAXN];
void init() {
for (int i = 2; i < MAXN; i++) {
if (!st[i]) p[idx++] = i;
for (int j = 0; j < idx && p[j] * i < MAXN; j++) {
st[i * p[j]] = true;
if (i % p[j] == 0) break;
}
}
}
int ksm(int a,int b) {
int ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
struct Node {
int l,r;// [l,r]
vector<PII> mp;// 优化2: 开mp见祖宗 (事实上unordered 也会寄)
int lcm;
Node(int _l,int _r):l(_l),r(_r){}
Node(int LL ,int rr ,vector<PII> vv,int Lcm):l(LL), r(rr),mp(vv),lcm(Lcm) {}
bool operator<(const Node &o) const {return l < o.l;}
};
set<Node> s;
#define IT set<Node>::iterator
IT split(int p) { // split [l,r] into [l,p-1] and [p,r]
IT it = s.lower_bound(Node(p,1));
if(it != s.end() && it->l == p) return it;
it --;
int L = it->l, R = it->r,lcm = it->lcm;
auto V = it->mp;
s.erase(it);
s.insert(Node(L,p - 1,V,lcm));
return s.insert(Node(p,R,V,lcm)).first;
}
void assign(int l,int r) {// 区间覆盖
IT end = split(r + 1),beg = split(l);// 一定要先split右边
int ans = 1;
vector<int> mp(MAXN,0);
for(auto it = beg;it != end;it ++) {
auto t = it->mp;
for(auto [x,y] : t) mp[x] = max(mp[x],y);
}
vector<PII> vec;
for(int i = 0;i < idx;i ++) if(mp[p[i]]) {
// cout << p[i] << " " << mp[p[i]] << endl;
ans = ans * ksm(p[i],mp[p[i]]) % mod;
vec.push_back({p[i],mp[p[i]]});
}
cout << ans << endl;
s.erase(beg,end);
s.insert(Node(l,r,vec,ans));
}
vector<PII> get(int x) {
vector<PII> vec;
for(int i = 0;i < idx;i ++) {
if(x % p[i] == 0) {
int e = 0;
while(x % p[i] == 0) {
x /= p[i];
e ++;
}
vec.push_back({p[i],e});
}
}
if(x != 1) vec.push_back({x,1});
// for(auto [x,y] : vec) cout << x << " " << y << endl;
return vec;
}
void solve()
{
init();
int n,q; cin >> n >> q;
rep(i,1,n) {
int x; cin >> x;
s.insert(Node(i,i,get(x),x));
}
s.insert(Node(n + 1,n + 1));
while(q --) {
int l,r; cin >> l >> r;
// 优化3:如果不会改变直接输出 主要建立在数据随机的基础上比较有效
auto it = s.upper_bound(Node(l,r));
it --;
if(it->r > r) {
cout << it->lcm << endl;
continue;
}
assign(l,r);
}
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//int T;cin>>T;
//while(T--)
solve();
return 0;
}