P9989 [Ynoi Easy Round 2023] TEST_69 题解

经典套路是一个数一直求 gcd\gcd,在 O(logV)O(\log V) 的变化次数内会变成 11。注意变化次数不是操作次数,也就是说这个数在操作过程中不同取值只有 O(logV)O(\log V)

考虑一个集合 S={s1,s2,,sn}S=\{s_1,s_2,\cdots,s_n\},现在要对里面每个数,与 kkgcd\gcd。容易发现的是,当 kk 是这些数共同的倍数时,操作无效,否则必然有数被影响。

kk 时这些数的共同倍数等价于 kk 是这些数最小公倍数的倍数。于是线段树维护区间 lcm\operatorname{lcm},修改时如果遇到操作无效直接退出,否则递归处理。显然一个数最多被修改 O(logV)O(\log V) 次,所以整体的复杂度是 O(mpolylogn)O(m \operatorname{polylog} n) 的。

范围比较大,我的做法需要 __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;
}
posted @   HappyBobb  阅读(32)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示