『做题记录』P9989 [Ynoi Easy Round 2023] TEST_69

累了,整道水的。(懒

[P9989 Ynoi Easy Round 2023] TEST_69

Description

给定一个长为 n 的序列 a ,有 m 次操作。

每次有两种操作:

1 l r x:对于区间 [l,r] 内所有 i ,将 ai 变成 gcd(ai,x)

2 l r:查询区间 [l,r] 的和,答案对 232 取模后输出。

1ai,x1018,1n,l,r2×105,1m5×105

Solution

  首先对于操作一,我们不难发现无效的操作其实是非常多的。因为 ai=gcd(ai,x) 这个操作如果使 ai 发生变化,那么 ai 是会变为至多 ai2 的,也就是说 ai 最多变化 logV 次,接下来就是考虑如何不去执行无用操作了。

  考虑到当 lcmlir(ai)|x 时,这一段区间都不会发生变化,因此我们只需要记录一下 lcm 即可判断是否修改。维护lcm的复杂度显然也是正确的,因为一个数lcm发生变化最多 logV 次,而大于 V 的我们就可以赋成 inf 了,因为此时 x 一定不是它的倍数,也就是说修改的复杂度是取lcm的复杂度 logV 乘上取lcm次数(线段树层数) logn

  总复杂度 O(nlognlogV)

Code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define mp make_pair
#define vi vector<int>
#define eb emplace_back
#define pii pair<int, int>
#define fi first
#define se second
#define Rep(rp,a,b) for(int rp=a;rp<b;++rp)
#define rep(rp,a,b) for(int rp=a;rp<=b;++rp)
#define per(bl,a,b) for(int bl=a;bl>=b;--bl)
mt19937 rnd(114514);
#define segc int mid = L+R>>1, lc = now<<1, rc = lc|1
const int N = 2e5+5, INF = 1e9;
const LL MOD = 1ll<<32;
template <typename T> inline void chkmin(T &x,T y) {x = y>x ? x : y;}
template <typename T> inline void chkmax(T &x,T y) {x = y>x ? y : x;}
inline LL read() {
	register LL x = 0, f = 1;
	register char ch = 0;
	while(ch < 48 || ch > 57) {
			ch = getchar();
			if (ch == '-') f = -1;
		}
	while(ch >= 48 && ch <= 57) x = x*10+(ch^48), ch = getchar();
	return f*x;
}

LL a[N];

LL _lcm(LL x, LL y) {
	if (x < 0 || y < 0 || (__int128)x/__gcd(x, y)*y > 1e18) return -1;
	return x/__gcd(x, y)*y;
}

struct BLCK{
	LL sum, lcm;
	BLCK operator +(const BLCK &x) const {
		return (BLCK){(sum+x.sum)%MOD, _lcm(lcm, x.lcm)};
	}
}tr[N<<2];

void build(int now, int L, int R) {
	if (L == R) {
		tr[now].sum = tr[now].lcm = a[L];
		return ;
	}
	segc;
	build(lc, L, mid), build(rc, mid+1, R);
	tr[now] = tr[lc]+tr[rc];
}

void update(int now, int L, int R, int ql, int qr, LL x) {
	if (qr < L || R < ql) return;
	if (tr[now].lcm > 0 && x%tr[now].lcm == 0) return;
	if (L == R) {
		tr[now].sum = tr[now].lcm = __gcd(tr[now].sum, x);
		return;
	}
	segc;
	update(lc, L, mid, ql, qr, x), update(rc, mid+1, R, ql, qr, x);
	tr[now] = tr[lc]+tr[rc];
}

LL query(int now, int L, int R, int ql, int qr) {
	if (qr < L || R < ql) return 0;
	if (ql <= L && R <= qr) return tr[now].sum;
	segc;
	return (query(lc, L, mid, ql, qr)+query(rc, mid+1, R, ql, qr))%MOD;
}

int main() {
	int n = read(), Q = read();
	rep (i, 1, n) a[i] = read();
	build(1, 1, n);
	while (Q --) {
		int opt = read(), ql = read(), qr = read();
		if (opt == 1) {
			LL x = read();
			update(1, 1, n, ql, qr, x);
		} else {
			printf("%lld\n", query(1, 1, n, ql, qr));
		}
	}
	return 0;
}

Summary

  what can i say

posted @   Black_Crow  阅读(9)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示