周记1
这个周我都忘了我做了啥了
唯一记得的:
Lougu P10463 Interval GCD
题目描述
给定一个长度为 \(N\) 的数列 \(a\),以及 \(M\) 条指令,每条指令可能是以下两种之一:
C l r d,表示把 \(a_l,a_{l+1},…,a_r\) 都加上 \(d\)。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;
}

浙公网安备 33010602011771号