2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛
给一个数列,三种操作:
- [l, r]区间每个数+k
- [l, r]区间和
- [l, r] 区间gcd
一看这不区间gcd裸题,我直接掏出线段树就往上冲,写了大半个小时然后就10分,非常离谱,兄弟
两个坑:l 和 r 可能是反的,gcd要取abs
upd : 刚开始觉得gcd取abs很离谱,后来想了想可能是因为原数组都是正数,然后因为差分了才出的负数gcd,所以答案要取abs
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e5 + 10;
ll a[N], b[N];
struct nodeGCD {
ll l, r;
ll ggcd;
};
nodeGCD trGCD[N << 2];
void pushupGCD(ll u) {
trGCD[u].ggcd = abs(__gcd(trGCD[u << 1].ggcd, trGCD[u << 1 | 1].ggcd));
}
void buildGCD(ll u, ll l, ll r) {
if (l == r) {
trGCD[u] = {l, r, b[r]};
} else {
trGCD[u] = {l, r, 0};
ll mid = (l + r) >> 1;
buildGCD(u << 1, l, mid);
buildGCD(u << 1 | 1, mid + 1, r);
pushupGCD(u);
}
}
void modifyGCD(ll u, ll l, ll r, ll k) {
if (trGCD[u].l >= l && trGCD[u].r <= r) {
trGCD[u].ggcd += k;
return;
}
ll mid = (trGCD[u].l + trGCD[u].r) >> 1;
if (l <= mid) modifyGCD(u << 1, l, r, k);
if (r > mid) modifyGCD(u << 1 | 1, l, r, k);
pushupGCD(u);
}
ll queryGCD(ll u, ll l, ll r) {
if (trGCD[u].l >= l && trGCD[u].r <= r) return trGCD[u].ggcd;
ll mid = (trGCD[u].l + trGCD[u].r) >> 1;
ll res = 0;
if (l <= mid) res = abs(__gcd(res, queryGCD(u << 1, l, r)));
if (r > mid) res = abs(__gcd(res, queryGCD(u << 1 | 1, l, r)));
return res;
}
struct node {
ll l, r;
ll sum;
ll tag;
};
node tr[N << 2];
void pushup(ll u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(ll u) {
auto &rt = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
left.tag += rt.tag;
left.sum += (left.r - left.l + 1) * rt.tag;
right.tag += rt.tag;
right.sum += (right.r - right.l + 1) * rt.tag;
rt.tag = 0;
}
void build(ll u, ll l, ll r) {
if (l == r) {
tr[u] = {l, r, a[r], 0};
} else {
tr[u] = {l, r, 0, 0};
ll mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(ll u, ll l, ll r, ll k) {
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].sum += k * (tr[u].r - tr[u].l + 1);
tr[u].tag += k;
return;
}
pushdown(u);
ll mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid) modify(u << 1, l, r, k);
if (r > mid) modify(u << 1 | 1, l, r, k);
pushup(u);
}
ll query(ll u, ll l, ll r) {
if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
pushdown(u);
ll mid = (tr[u].l + tr[u].r) >> 1;
ll sum = 0;
if (l <= mid) sum = (sum + query(u << 1, l, r));
if (r > mid) sum = (sum + query(u << 1 | 1, l, r));
return sum;
}
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
ll n, q;
cin >> n >> q;
for (ll i = 1; i <= n; ++i)
cin >> a[i];
build(1, 1, n + 5);
for (ll i = 1; i <= n; ++i) {
b[i] = a[i] - a[i - 1];
}
// b[1] = 0;
buildGCD(1, 1, n + 5);
while (q--) {
ll op, l, r, k;
cin >> op >> l >> r;
if (l > r) swap(l, r);
if (op == 0) {
cin >> k;
modifyGCD(1, l, l, k);
modifyGCD(1, r + 1, r + 1, -k);
modify(1, l, r, k);
} else if (op == 1) {
cout << query(1, l, r) << endl;
} else if (op == 2) {
ll val = query(1, l, l);
// cerr << val << " " << queryGCD(1, l + 1, r) << endl;
// cerr << "l " <<l << " "<< r << endl;
if (l == r) cout << val << endl;
else cout << __gcd(val, queryGCD(1, l + 1, r)) << endl;
}
}
}