数列分块入门

分块入门

LibreOJ - 6277

#include <bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T& t)
{
    int f = 0, c = getchar();
    t = 0;
    while (!isdigit(c)) f |= c == '-', c = getchar();
    while (isdigit(c)) t = t * 10 + c - 48, c = getchar();
    if (f) t = -t;
}
const int N = 5e4 + 100;
int bk, num;
int n, a[N], L[N], R[N], pos[N], lazy[N];
inline void build()
{
    bk = sqrt(n);
    num = n / bk;
    if(n % bk) num++;
    for(int i = 1; i <= num; ++i)
    {
        L[i] = (i - 1) * bk + 1;
        R[i] = i * bk;
    }
    R[num] = n;
    for(int i = 1; i <= n; ++i) pos[i] = (i - 1) / bk + 1;
}
inline void change(int l, int r, int k)
{
    int idx1 = pos[l];
    int idx2 = pos[r];
    if(idx1 == idx2)
    {
        for(int i = l; i <= r; ++i) a[i] += k;
    }
    else
    {
        for(int i = l; i <= R[idx1]; ++i) a[i] += k;
        for(int i = pos[l] + 1; i <= pos[r] - 1; ++i) lazy[i] += k;
        for(int i = L[idx2]; i <= r; ++i) a[i] += k;
    }
}
inline int query(int i)
{
    int idx = pos[i];
    return lazy[idx] ? lazy[idx] + a[i] : a[i];
}
signed main()
{
    read(n);
    for(int i = 1; i <= n; ++i) read(a[i]);
    build();
    int op, l, r, c;
    for(int i = 1; i <= n; ++i)
    {
        read(op), read(l), read(r), read(c);
        if(op == 0)
        {
            change(l, r, c);
        }
        else printf("%d\n", query(r));
    }
    return 0;
}

LibreOJ - 6278

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
//bk:块大小 num:块数量
int bk, num;
//每个块的左端点L 右端点R 位于哪个块pos 每个块的lazy标记
int n, a[N], L[N], R[N], pos[N], lazy[N];
vector<int> g[N];//排序桶块 将每一块的元素扔进一个桶 然后排序
inline void build()
{
    bk = sqrt(n);
    num = n / bk;// n / 块大小 = 块数
    if(n % bk) num++; // 如果不能整除 代表多了一个块
    for(int i = 1; i <= num; ++i)
    {
        L[i] = (i - 1) * bk + 1;
        R[i] = i * bk;
    }
    R[num] = n;
    for(int i = 1; i <= n; ++i) pos[i] = (i - 1) / bk + 1;//处理位置
    for(int i = 1; i <= num; ++i)
    {
        for(int j = L[i]; j <= R[i]; ++j) g[i].push_back(a[j]);
        sort(g[i].begin(), g[i].end());
    }
}
//暴力再更新这个块内的排序
inline void resort(int i)
{
    g[i].clear();
    for(int j = L[i]; j <= R[i]; ++j) g[i].push_back(a[j]);
    sort(g[i].begin(), g[i].end());
}
inline void change(int x, int y, int c)
{
    //如果在同一个块内 暴力更新
    if(pos[x] == pos[y])
    {
        for(int i = x; i <= y; ++i) a[i] += c;
        resort(pos[x]);
        return;
    }
    //暴力更新左边
    for(int i = x; i <= R[pos[x]]; ++i) a[i] += c;
    resort(pos[x]);
    //对于中间完整的块打上lazy tag
    for(int i = pos[x] + 1; i < pos[y]; ++i) lazy[i] += c;
    //暴力更新右边
    for(int i = L[pos[y]]; i <= y; ++i) a[i] += c;
    resort(pos[y]);
}
inline int query(int x, int y, int c)
{
    int res = 0;
    //如果在同一块内
    if(pos[x] == pos[y])
    {
        for(int i = x; i <= y; ++i) res += (a[i] + lazy[pos[x]] < c);
        return res;
    }
    //左边
    for(int i = x; i <= R[pos[x]]; ++i) res += (a[i] + lazy[pos[x]] < c);
    //中间
    for(int i = pos[x] + 1; i < pos[y]; ++i)
    {
        int k = lower_bound(g[i].begin(), g[i].end(), c - lazy[i]) - g[i].begin();
        res += k;
    }
    //右边
    for(int i = L[pos[y]]; i <= y; ++i) res += (a[i] + lazy[pos[y]] < c);
    return res;
}
signed main()
{
    cin >> n;
    for(int i = 1; i <= n; ++i) cin >> a[i];
    build();
    int op, l, r, c;
    for(int i = 1; i <= n; ++i)
    {
        cin >> op >> l >> r >> c;
        if(op == 0) change(l, r, c);
        else cout << query(l, r, c * c) << "\n";
    }
    return 0;
}


posted @ 2022-07-04 10:04  std&ice  阅读(87)  评论(0)    收藏  举报