数硬币 - 2022年 GPLT 上海理工校内选拔 - 区间修改gcd

2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛

数硬币

给一个数列,三种操作:

  1. [l, r]区间每个数+k
  2. [l, r]区间和
  3. [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;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值