P9989 [Ynoi Easy Round 2023] TEST_69 题解
经典套路是一个数一直求 ,在 的变化次数内会变成 。注意变化次数不是操作次数,也就是说这个数在操作过程中不同取值只有 。
考虑一个集合 ,现在要对里面每个数,与 求 。容易发现的是,当 是这些数共同的倍数时,操作无效,否则必然有数被影响。
时这些数的共同倍数等价于 是这些数最小公倍数的倍数。于是线段树维护区间 ,修改时如果遇到操作无效直接退出,否则递归处理。显然一个数最多被修改 次,所以整体的复杂度是 的。
范围比较大,我的做法需要 __int128。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <climits>
#include <numeric>
#include <vector>
#ifndef ONLINE_JUDGE
#include <__msvc_int128.hpp>
#endif
#include <cstring>
using namespace std;
const int N = 2e5 + 5;
#ifdef ONLINE_JUDGE
#define _Signed128 __int128
#endif
const _Signed128 MOD = (1LL << 32);
_Signed128 mygcd(_Signed128 a, _Signed128 b)
{
return (b == 0 ? a : mygcd(b, a % b));
}
_Signed128 mylcm(_Signed128 a, _Signed128 b)
{
return a / mygcd(a, b) * b;
}
int n, m;
long long a[N];
class SegmentTree
{
public:
struct Node
{
int l, r;
_Signed128 sum;
bool bg;
_Signed128 cm;
}tr[N << 2];
void pushup(int u)
{
tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % MOD;
tr[u].cm = mylcm(tr[u << 1].cm, tr[u << 1 | 1].cm);
tr[u].bg = tr[u << 1].bg || tr[u << 1 | 1].bg || (tr[u].cm > static_cast<_Signed128>(static_cast<long long>(1e18)));
}
void build(int u, int l, int r)
{
tr[u] = { l, r, a[l] % MOD, 0, static_cast<_Signed128>(a[l]) };
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void update(int u, int l, int r, _Signed128 k)
{
if (!tr[u].bg && k % tr[u].cm == 0) return;
if (tr[u].l == tr[u].r)
{
_Signed128 val = mygcd(k, (_Signed128)tr[u].cm);
tr[u].sum = val % MOD;
tr[u].cm = val;
tr[u].bg = 0;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) update(u << 1, l, r, k);
if (r > mid) update(u << 1 | 1, l, r, k);
pushup(u);
}
_Signed128 query(int u, int l, int r)
{
if (tr[u].l >= l and tr[u].r <= r) return tr[u].sum % MOD;
int mid = tr[u].l + tr[u].r >> 1;
_Signed128 sum = 0;
if (l <= mid) sum = query(u << 1, l, r);
if (r > mid) sum = (sum + query(u << 1 | 1, l, r)) % MOD;
return sum;
}
}sgt;
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
sgt.build(1, 1, n);
while (m--)
{
int op, l, r;
cin >> op >> l >> r;
if (op == 1)
{
long long k;
cin >> k;
sgt.update(1, l, r, static_cast<_Signed128>(k));
}
else
{
cout << (long long)sgt.query(1, l, r) << "\n";
}
}
return 0;
}

浙公网安备 33010602011771号