分块入门学习笔记

分块入门学习笔记

前言

感觉我还是比较喜欢这种几乎不用怎么动脑的暴力数据结构啊
例题
给出一个长为 \(n\) 的序列和 \(n\) 次操作。
设计一种数据结构,满足区间加法和区间求和。
\(1 \leq n \leq 50000\)

分析

一开始也是觉得搞个线段树或者树状数组不就行了吗,后面发现分块还可以搞一些其他的操作可惜蒟蒻现在还不会
进入正题
分块,顾名思义就是把一个序列分成若干块来操作,那么我们要如何做呢。
首先,我们把序列分成若干块,每一块有 \(\sqrt{n}\) 个数。
对于每一块,我们维护一个 \(lazy\)\(sum\) 表示懒标记和区间和。
每次修改时,如果覆盖了某一块,那么直接用懒标记标记一下和区间加和一下,如果不在就一个个加。
查询同上。

code

#include <bits/stdc++.h>
#define LL long long
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
#define fd(x , y , z) for(int x = y ; x >= z ; x --)
using namespace std;
const int N = 100005;
LL n, n1, a[N];
struct note {
    LL v, lay;
    int l, r;
} mark[N];
LL read() {
    LL val = 0, fu = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            fu = -1;

        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        val = val * 10 + (ch - '0');
        ch = getchar();
    }

    return val * fu;
}
void change(LL l, LL r, LL val) {
    int l1 = l / n1 + 1, r1 = r / n1 + 1;
    if (l1 == r1) {
        mark[l1].v += val * (r - l + 1);
        fu(i, l, r)
            a[i] += val;
    } 
    else {
        fu(i, l1 + 1, r1 - 1)
            mark[i].v += val * (mark[i].r - mark[i].l + 1), mark[i].lay += val;
        change(l, mark[l1].r, val);
        change(mark[r1].l, r, val);
    }
}
LL query(LL l, LL r, LL val) {
    LL ans = 0;
    int l1 = l / n1 + 1, r1 = r / n1 + 1;
    if (l1 == r1) {
        if (l == mark[l1].l && r == mark[l1].r)
            return mark[l1].v;
        fu(i, l, r)
            ans = ((ans + a[i]) % val + mark[l1].lay) % val;
    } 
    else {
        fu(i, l1 + 1, r1 - 1)
        ans = (ans + mark[i].v) % val;
        ans = (ans + query (l , mark[l1].r , val)) % val;
        ans = (ans + query (mark[r1].l , r , val)) % val;
    }
    return ans;
}
int main() {
    // freopen ("a2.in" , "r" , stdin);
    // freopen ("a.out" , "w" , stdout);
    int num;
    n = read();
    n1 = sqrt(n);
    mark[1].l = 1;
    fu(i, 1, n) {
        a[i] = read();
        num = (i / n1 + 1);
        mark[num].v += a[i];

        if (i % n1 == 0)
            mark[num].l = i;

        mark[num].r = i;
    }
    LL opt, l, r, c;
    fu(i, 1, n) {
        opt = read(), l = read(), r = read(), c = read();
        if (!opt)
            change(l, r, c);
        else
            printf("%lld\n", query(l, r, c + 1));
    }
}
posted @ 2023-04-20 21:05  2020fengziyang  阅读(15)  评论(0编辑  收藏  举报