QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: Lynn_Sue

Posted at: 2026-09-06 21:11:27

Last updated: 2026-09-06 21:37:26

Back to Problem

本题可以放入门组模拟赛,理由如下:

根本不需要什么树状数组。

考虑数组和差分两种做法。一种是 $O(n)$ 区间修 $O(1)$ 单点求值。一种是 $O(1)$ 区间修 $O(n)$ 求值。

我们可以给出第一个优化:如果询问 $\le \dfrac{q}{2}$ 次用第一种方法。否则用第二种方法。

这样可以做到不超过 $\dfrac{nq}{2}$。实测跑了 $762 \text{ms}$。

还能优化吗?当然可以啦。如果是 $5 \times 10^9$ 次的运算,就不会有这篇题解了。

算法一可以优化常数。如果区间长度 $\leq \dfrac{n}{2}$,可以直接加。否则可以全局打个标记,对区间外的减。

算法二也可以优化常数。如果查询的点在前一半,可以直接加差分,否则维护最后一个数的值,从后往前减。

那么这样就等价于 $n$ 和 $q$ 都变成了 $5 \times 10^4$。而时限竟然有足足 $2\text{s}$!这意味着极限数据下 $O(nq)$ 也可以轻松在 QOJ 上通过。实测跑到了 $367\text{ms}$。

至此,不会树状数组的我们解决了这个题。

#include<bits/stdc++.h>
using namespace std;
int n, m, cnt;
long long a[100005], cf[100005], tag, sum;
struct que{
    int op, l, r, k, pos;
}Q[100005];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    cin >> m;
    for (int i = 1; i <= m; i++){
        cin >> Q[i].op;
        if (Q[i].op == 1)
            cin >> Q[i].l >> Q[i].r >> Q[i].k;
        else{
            cin >> Q[i].pos;
            cnt++;
        }
    }
    if (cnt <= (n / 2)){
        for (int i = 1; i <= n; i++)
            cf[i] = a[i] - a[i - 1];
        sum = a[n];
        for (int _ = 1; _ <= m; _++){
            int op = Q[_].op;
            if (op == 1){
                int l = Q[_].l, r = Q[_].r, k = Q[_].k;
                cf[l] += k;
                cf[r + 1] -= k;
                if (r >= n)
                    sum += k;
            }else{
                int pos = Q[_].pos;
                long long ans = 0;
                if (pos <= n / 2){
                    for (int i = 1; i <= pos; i++)
                        ans += cf[i];
                }else{
                    ans = sum;
                    for (int i = n; i > pos; i--)
                        ans -= cf[i];
                }
                cout << ans << "\n";
            }
        }
    }else{
        for (int _ = 1; _ <= m; _++){
            int op = Q[_].op;
            if (op == 1){
                int l = Q[_].l, r = Q[_].r, k = Q[_].k;
                if (r - l <= (n / 2)){
                    for (int i = l; i <= r; i++)
                        a[i] += k;
                }else{
                    tag += k;
                    for (int i = 1; i < l; i++)
                        a[i] -= k;
                    for (int i = n; i > r; i--)
                        a[i] -= k;    
                }
            }else if (op == 2){
                int pos = Q[_].pos;
                cout << a[pos] + tag << "\n";
            }
        }
    }
    return 0;
}

Comments

No comments yet.