题解:BISHI129 区间增量与区间小于计数

题目链接

区间增量与区间小于计数

题目描述

给定长度为 的数组 ,支持两类操作:

  • 区间增量:将 内每个元素加上
  • 区间小于计数:统计 内有多少个元素

解题思路

使用分块(根号分解)+ 块内有序表 + 块懒标记:

  • 将数组按块大小 划分为若干块,每块维护:
    • 原始值数组片段
    • 懒标记 (整块平移量);
    • 按当前“基值”排序的有序表,以支持整块二分计数。
  • 区间加:
    • 若跨多块,仅对两端零星块逐元素加并“重建”有序表;
    • 对中间完整块,直接累加懒标记。
  • 区间计数:
    • 两端零星块逐元素判断
    • 中间完整块用二分统计有序表中 的数量。

复杂度:每次操作 ,取 得均摊 ,能通过本题。

代码

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, q; if(!(cin >> n >> q)) return 0;
    vector<i64> a(n+1);
    for(int i=1;i<=n;i++) cin >> a[i];

    int B = max(1, (int)sqrt(n));
    int num = (n + B - 1) / B;
    vector<int> L(num+1), R(num+1), id(n+1);
    for(int b=1;b<=num;b++){
        L[b] = (b-1)*B + 1;
        R[b] = min(n, b*B);
        for(int i=L[b]; i<=R[b]; i++) id[i]=b;
    }
    vector<i64> tag(num+1, 0);
    vector<vector<i64>> ord(num+1);
    auto rebuild = [&](int b){
        ord[b].clear(); ord[b].reserve(R[b]-L[b]+1);
        for(int i=L[b]; i<=R[b]; i++) ord[b].push_back(a[i]);
        sort(ord[b].begin(), ord[b].end());
    };
    for(int b=1;b<=num;b++) rebuild(b);

    auto range_add = [&](int l, int r, i64 x){
        int bl = id[l], br = id[r];
        if(bl==br){
            for(int i=l;i<=r;i++) a[i]+=x;
            rebuild(bl);
            return;
        }
        for(int i=l;i<=R[bl];i++) a[i]+=x; rebuild(bl);
        for(int i=L[br];i<=r;i++) a[i]+=x; rebuild(br);
        for(int b=bl+1;b<=br-1;b++) tag[b]+=x;
    };

    auto count_less = [&](int l, int r, i64 x){
        long long ans = 0;
        int bl = id[l], br = id[r];
        if(bl==br){
            for(int i=l;i<=r;i++) if(a[i]+tag[bl] < x) ans++;
            return ans;
        }
        for(int i=l;i<=R[bl];i++) if(a[i]+tag[bl] < x) ans++;
        for(int i=L[br];i<=r;i++) if(a[i]+tag[br] < x) ans++;
        for(int b=bl+1;b<=br-1;b++){
            i64 t = x - tag[b];
            ans += lower_bound(ord[b].begin(), ord[b].end(), t) - ord[b].begin();
        }
        return ans;
    };

    while(q--){
        int op; cin >> op;
        if(op==1){ int l,r; i64 x; cin >> l >> r >> x; range_add(l,r,x); }
        else { int l,r; i64 x; cin >> l >> r >> x; cout << count_less(l,r,x) << '\n'; }
    }
    return 0;
}
import java.io.*;
import java.util.*;

public class Main {
    static class FastScanner {
        private final InputStream in; private final byte[] buf = new byte[1<<16];
        private int p=0,l=0; FastScanner(InputStream is){in=is;}
        private int read() throws IOException { if(p>=l){ l=in.read(buf); p=0; if(l<=0) return -1; } return buf[p++]; }
        int nextInt() throws IOException { int c; int s=1,x=0; do{c=read();}while(c<=32); if(c=='-'){s=-1;c=read();} while(c>32){ x=x*10+(c-'0'); c=read(); } return x*s; }
        long nextLong() throws IOException { int c; long s=1,x=0; do{c=read();}while(c<=32); if(c=='-'){s=-1;c=read();} while(c>32){ x=x*10+(c-'0'); c=read(); } return x*s; }
    }

    public static void main(String[] args) throws Exception {
        FastScanner fs = new FastScanner(System.in);
        int n = fs.nextInt();
        int q = fs.nextInt();
        long[] a = new long[n+1];
        for(int i=1;i<=n;i++) a[i]=fs.nextLong();
        int B = Math.max(1, (int)Math.sqrt(n));
        int num = (n + B - 1) / B;
        int[] L = new int[num+1], R = new int[num+1], id = new int[n+1];
        for(int b=1;b<=num;b++){
            L[b] = (b-1)*B + 1;
            R[b] = Math.min(n, b*B);
            for(int i=L[b]; i<=R[b]; i++) id[i]=b;
        }
        long[] tag = new long[num+1];
        long[][] ord = new long[num+1][];
        for(int b=1;b<=num;b++){
            int len = R[b]-L[b]+1;
            long[] v = new long[len];
            for(int i=0;i<len;i++) v[i] = a[L[b]+i];
            Arrays.sort(v); ord[b]=v;
        }
        Runnable rebuild = new Runnable(){ public void run(){} };
        final class Helper{
            void rebuild(int b){
                int len = R[b]-L[b]+1; long[] v = new long[len];
                for(int i=0;i<len;i++) v[i] = a[L[b]+i];
                Arrays.sort(v); ord[b]=v;
            }
            int lowerBound(long[] v, long val){
                int l=0, r=v.length;
                while(l<r){ int m=(l+r)>>>1; if(v[m]<val) l=m+1; else r=m; }
                return l;
            }
        }
        Helper hp = new Helper();

        while(q-- > 0){
            int op = fs.nextInt();
            if(op==1){
                int l = fs.nextInt(), r = fs.nextInt(); long x = fs.nextLong();
                int bl = id[l], br = id[r];
                if(bl==br){ for(int i=l;i<=r;i++) a[i]+=x; hp.rebuild(bl); }
                else{
                    for(int i=l;i<=R[bl];i++) a[i]+=x; hp.rebuild(bl);
                    for(int i=L[br];i<=r;i++) a[i]+=x; hp.rebuild(br);
                    for(int b=bl+1;b<=br-1;b++) tag[b]+=x;
                }
            }else{
                int l = fs.nextInt(), r = fs.nextInt(); long x = fs.nextLong();
                int bl = id[l], br = id[r]; long ans=0;
                if(bl==br){ for(int i=l;i<=r;i++) if(a[i]+tag[bl] < x) ans++; }
                else{
                    for(int i=l;i<=R[bl];i++) if(a[i]+tag[bl] < x) ans++;
                    for(int i=L[br];i<=r;i++) if(a[i]+tag[br] < x) ans++;
                    for(int b=bl+1;b<=br-1;b++){
                        long t = x - tag[b];
                        ans += hp.lowerBound(ord[b], t);
                    }
                }
                System.out.println(ans);
            }
        }
    }
}
import sys, math, bisect

data = sys.stdin.buffer.read().split()
it = iter(data)
n = int(next(it)); q = int(next(it))
a = [0]*(n+1)
for i in range(1, n+1):
    a[i] = int(next(it))

B = max(1, int(math.isqrt(n)))
num = (n + B - 1) // B
L = [0]*(num+1)
R = [0]*(num+1)
bid = [0]*(n+1)
for b in range(1, num+1):
    L[b] = (b-1)*B + 1
    R[b] = min(n, b*B)
    for i in range(L[b], R[b]+1):
        bid[i] = b

tag = [0]*(num+1)
ordv = [[] for _ in range(num+1)]
def rebuild(b: int):
    v = [a[i] for i in range(L[b], R[b]+1)]
    v.sort()
    ordv[b] = v

for b in range(1, num+1):
    rebuild(b)

def range_add(l: int, r: int, x: int):
    bl, br = bid[l], bid[r]
    if bl == br:
        for i in range(l, r+1):
            a[i] += x
        rebuild(bl)
        return
    for i in range(l, R[bl]+1):
        a[i] += x
    rebuild(bl)
    for i in range(L[br], r+1):
        a[i] += x
    rebuild(br)
    for b in range(bl+1, br):
        tag[b] += x

def count_less(l: int, r: int, x: int) -> int:
    bl, br = bid[l], bid[r]
    ans = 0
    if bl == br:
        for i in range(l, r+1):
            if a[i] + tag[bl] < x:
                ans += 1
        return ans
    for i in range(l, R[bl]+1):
        if a[i] + tag[bl] < x:
            ans += 1
    for i in range(L[br], r+1):
        if a[i] + tag[br] < x:
            ans += 1
    for b in range(bl+1, br):
        t = x - tag[b]
        ans += bisect.bisect_left(ordv[b], t)
    return ans

out = []
for _ in range(q):
    op = int(next(it))
    if op == 1:
        l = int(next(it)); r = int(next(it)); x = int(next(it))
        range_add(l, r, x)
    else:
        l = int(next(it)); r = int(next(it)); x = int(next(it))
        out.append(str(count_less(l, r, x)))

sys.stdout.write("\n".join(out))

算法及复杂度

  • 算法:根号分解 + 懒标记 + 块内有序表二分
  • 时间复杂度: 均摊
  • 空间复杂度: