周记1

这个周我都忘了我做了啥了

唯一记得的:

Lougu P10463 Interval GCD

题目描述

给定一个长度为 \(N\) 的数列 \(a\),以及 \(M\) 条指令,每条指令可能是以下两种之一:

  1. C l r d,表示把 \(a_l,a_{l+1},…,a_r\) 都加上 \(d\)
  2. Q l r,表示询问 \(a_l,a_{l+1},…,a_r\) 的最大公约数(\(\gcd\))。

对于每个询问,输出一个整数表示答案。

输入格式

第一行两个整数 \(N,M\)

第二行 \(N\) 个整数,分别表示 \(a_1,a_2,\dots,a_N\)

接下来 \(M\) 行表示 \(M\) 条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案,每个答案占一行。

输入输出样例

输入 #1

5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4

输出 #1

1
2
4

说明/提示

对于 \(100\%\) 的测试数据,\(N \le 5\times10^5\)\(M \le 10^5\)\(1 \le a_i \le 10^{18}\)\(|d| \le 10^{18}\),保证数据在计算过程中不会超过 long long 范围。

TJ

显然如果是单点加而不是区间加,我们就可以直接维护。

当前节点的 \(\gcd\) \(=\) 左儿子的 \(\gcd\) 和右儿子的 \(\gcd\)\(\gcd\)

区间加呢?

只需要把去区间加转换成单点加。

所以我们可以考虑差分。

假设原区间是 \(a_l, a_{l + 1},\dots , a_r\)

则差分区间是 \(a_l, a_{l + 1} - a_l,\dots , a_r - a_{r - 1}\)

设原区间的 \(\gcd = d\),差分区间的 \(\gcd = d_1\)

所以 \(d\mid a_i\)

所以 \(d\mid a_i - a_{i - 1}\)

所以 \(d\) 是差分区间的公因数,所以 \(d\) \(\leq\) \(d_1\)

又因为 \(d_1\mid a_l\),且 \(d_1\mid a_{l + 1} - a_l\)

所以 \(d_1\mid a_{l + 1}\)

以此类推, \(d_1\mid a_i\)

所以 \(d_1\) 是原区间的公因数。

所以 \(d_1\leq d\)

所以 \(d_1 = d\)

我们便证明了,差分区间的最大公因数 \(=\) 原区间的最大公因数。

点击查看代码
#include <iostream>
#include <algorithm>
#include <cmath>
#define int long long

using std::cin;
using std::cout;
typedef long long ll;
const int N = 5e5 + 10;

int ggcd(ll x, ll y)
{
	if (x < 0)
		x = -x;
	if (y < 0)
		y = -y;
	if (x == 0)
		return y;
	if (y == 0)
		return x;
	return ggcd(y, x % y);
}

struct Node
{
	ll gcd;
	ll sum;
	void init(ll x)
	{
		gcd = x;
		sum = x;
	}
	friend Node operator+(const Node &a, const Node &b)
	{
		Node ret;
		ret.gcd = ggcd(a.gcd, b.gcd);
		ret.sum = a.sum + b.sum;
		return ret;
	}
} z[N << 2];

ll a[N];
ll cf[N];

#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

void build(int l, int r, int rt)
{
	if (l == r)
	{
		z[rt].init(cf[l]);
		return;
	}
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
	z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
void modify(int l, int r, int rt, int p, ll k)
{
	if (l == r)
	{
		z[rt].gcd += k;
		z[rt].sum += k;
		return;
	}
	int m = (l + r) >> 1;
	if (p <= m)
		modify(lson, p, k);
	else
		modify(rson, p, k);
	z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
Node query(int l, int r, int rt, int nowl, int nowr)
{
	if (nowl <= l && r <= nowr)
		return z[rt];
	int m = (l + r) >> 1;
	if (nowl <= m)
	{
		if (nowr > m)
			return query(lson, nowl, nowr) + query(rson, nowl, nowr);
		else
			return query(lson, nowl, nowr);
	}
	else
		return query(rson, nowl, nowr);
}

signed main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	for (int i = 1; i <= n; ++i)
		cf[i] = a[i] - a[i - 1];
	build(root);
	while (m--)
	{
		char opt;
		cin >> opt;
		int l, r;
		cin >> l >> r;
		if (opt == 'C')
		{
			ll d;
			cin >> d;
			modify(root, l, d);
			if (r < n)
				modify(root, r + 1, -d);
		}
		else if (opt == 'Q')
		{
			if (l == r)
				cout << abs(query(root, 1, l).sum) << '\n';
			else
				cout << ggcd(query(root, 1, l).sum, query(root, l + 1, r).gcd) << '\n';
		}
	}
	return 0;
}
posted @ 2025-05-12 12:44  SigmaToT  阅读(27)  评论(0)    收藏  举报