牛客训练赛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;
}
posted @ 2022-06-10 22:58  Mxrurush  阅读(42)  评论(0编辑  收藏  举报