数列分块入门1-9 LibreOJ

数列分块入门1-9 LibreOJ

我也不知道为什么一个大二的ACM选手没学分块。

我怎么记得大一的时候,学长教给我的分块就只有 block 和 num 两个变量来着...好吧,应该是我没认真学。正好前两天朋友给学弟开课,乘机去蹭了一节课。然后...我还是不会哇,菜的一塌糊涂。

还是卿学姐好哇,多听几遍,睡得贼香

分块原理

分块嘛,其实就是优雅的暴力,和莫队(不会)有点异曲同工的赶脚。通过将数组分成小块以降低复杂度。

通常情况下:

  • 每个块的大小(block)为 \(\sqrt{n}\)
  • 块数(num)为 \(\sqrt{n}\)或\(\sqrt{n}+1\)
  • 每个块的左端点(L[x])为 \((i-1)*block+1\)
  • 每个块的右端点(R[x])为 \(i*block\)(最后一块右端点为\(n\))
  • 位置 x 上的数属于(belong[x])第 \((i-1)/block+1\) 块

每次修改或查询的时候如果需要维护 [L, R] 的数,如果L、R被分在了同一块,那么就直接暴力跑就行了,反正复杂度不会超过\(\sqrt{n}\)。

如果不在一块,那就先暴力更新所有和 L 同一块且位置在 L 之后的数,再更新所有和 R 在同一块且位置在 R 之前的数,最后,再去把这中间的若干块直接按“块”更新(利用新数组之类的)。这样的复杂度也只有 \(\sqrt{n}\)量级。从而完成多次优雅的在线更新和查询。

LOJ 6277 区间加法更新 单点查询

没啥好些的,就按照上边写的来就行。因为是纯板子题,所以还是放个代码好了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 5e4 + 5;

int belong[maxn];
int block, num;
int l[maxn], r[maxn];
int n;
int a[maxn];
int more[maxn];

void build() {
    block = sqrt(n);
    num = n / block;
    if (n % block != 0) {
        num++;
    }
    for (int i = 1; i <= num; i++) {
        l[i] = (i - 1) * block + 1;
        r[i] = i * block;
    }
    r[num] = n;
    for (int i = 1; i <= n; i++) {
        belong[i] = (i - 1) / block + 1;
    }
}

void update(int l, int r, int c) {
    if (belong[l] == belong[r]) {
        for (int i = l; i <= r; i++) {
            a[i] += c;
        }
        return;
    }
    for (int i = l; belong[i] == belong[l]; i++) {
        a[i] += c;
    }
    for (int i = r; belong[i] == belong[r]; i--) {
        a[i] += c;
    }
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        more[i] += c;
    }
}

int query(int x) {
    return a[x] + more[belong[x]];
}

int main() {
    while (~scanf("%d", &n)) {
        memset(more, 0, sizeof(more));
        memset(belong, 0, sizeof(belong));
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        build();
        for (int i = 1; i <= n; i++) {
            int f, l, r, c;
            scanf("%d%d%d%d", &f, &l, &r, &c);
            if (f == 0) {
                update(l, r, c);
            } else {
                printf("%d\n", query(r));
            }
        }
    }
    return 0;
}

LOJ 6278 区间加法更新 区间查询

需要 vector 数组进行区间排序,然后 lower_bound 二分找答案就行了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 5e4 + 5;

int belong[maxn];
int block, num;
int l[maxn], r[maxn];
int a[maxn];
int more[maxn];
vector<int> v[maxn];
int n;

void build() {
    block = sqrt(n);
    num = n / block;
    if (n % block != 0) {
        num++;
    }
    for (int i = 1; i <= num; i++) {
        l[i] = (i - 1) * block + 1;
        r[i] = i * block;
    }
    r[num] = n;
    for (int i = 1; i <= n; i++) {
        belong[i] = (i - 1) / block + 1;
        v[belong[i]].push_back(a[i]);
    }
    for (int i = 1; i <= num; i++) {
        sort(v[i].begin(), v[i].end());
    }
}

void pushup(int x) {
    v[x].clear();
    for (int i = l[x]; i <= r[x]; i++) {
        v[x].push_back(a[i]);
    }
    sort(v[x].begin(), v[x].end());
}

void update(int l, int r, int c) {
    if (belong[l] == belong[r]) {
        for (int i = l; i <= r; i++) {
            a[i] += c;
        }
        pushup(belong[l]);
        return;
    }
    for (int i = l; belong[i] == belong[l]; i++) {
        a[i] += c;
    }
    pushup(belong[l]);
    for (int i = r; belong[i] == belong[r]; i--) {
        a[i] += c;
    }
    pushup(belong[r]);
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        more[i] += c;
    }
}

int query(int l, int r, int c) {
    int ans = 0;
    if (belong[l] == belong[r]) {
        for (int i = l; i <= r; i++) {
            if (a[i] + more[belong[i]] < c) {
                ans++;
            }
        }
        return ans;
    }
    for (int i = l; belong[i] == belong[l]; i++) {
        if (a[i] + more[belong[i]] < c) {
            ans++;
        }
    }
    for (int i = r; belong[i] == belong[r]; i--) {
        if (a[i] + more[belong[i]] < c) {
            ans++;
        }
    }
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        int temp = c - more[i];
        ans += lower_bound(v[i].begin(), v[i].end(), temp) - v[i].begin();
    }
    return ans;
}

int main() {
    while (~scanf("%d", &n)) {
        memset(more, 0, sizeof(more));
        memset(belong, 0, sizeof(belong));
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        build();
        for (int i = 1; i <= n; i++) {
            int f, l, r;
            int c;
            scanf("%d%d%d%d", &f, &l, &r, &c);
            if (f == 0) {
                update(l, r, c);
            } else {
                printf("%d\n", query(l, r, c * c));
            }
        }
    }
    return 0;
}

LOJ 6279 区间加法更新 区间查询

几乎和第二题没差,就不上代码了。

LOJ 6280 区间加法更新 区间查询

几乎和第一题没差,需要维护每个块的和 s 数组,查询区间和。

LOJ 6281 区间开方更新 区间查询

这题相对前几题来说要难上不少,刚开始做的时候没反应过来,后来开方操作最多只会做64次,那么就肯定可以暴力了,不过需要标记整个块里是不是只有 0或1 (不需要开方操作了)。然后就是正常的区间加法,毕竟分块就是暴力哇。

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

const int maxn = 5e4 + 5;

int belong[maxn];
int L[maxn], R[maxn];
int a[maxn];
int n;
int block, num;
int s[maxn];
int mark[maxn];  // 标记 1 为区间中只有 0 或 1

void build() {
    block = sqrt(n);
    num = n / block;
    if (n % block) {
        num++;
    }
    for (int i = 1; i <= num; i++) {
        L[i] = (i - 1) * block + 1;
        R[i] = i * block;
    }
    R[num] = n;
    for (int i = 1; i <= n; i++) {
        belong[i] = (i - 1) / block + 1;
        s[belong[i]] += a[i];
    }
}

void update(int l, int r) {
    if (belong[l] == belong[r]) {
        if (mark[belong[l]] == 0) {
            mark[belong[l]] = 1;
            for (int i = l; i <= r; i++) {
                s[belong[i]] -= a[i];
                a[i] = sqrt(a[i]);
                s[belong[i]] += a[i];
            }
            for (int i = L[belong[l]]; i <= R[belong[l]]; i++) {
                if (a[i] > 1)
                    mark[belong[l]] = 0;
            }
        }
        return;
    }
    if (mark[belong[l]] == 0) {
        mark[belong[l]] = 1;
        for (int i = l; belong[i] == belong[l]; i++) {
            s[belong[i]] -= a[i];
            a[i] = sqrt(a[i]);
            s[belong[i]] += a[i];
        }
        for (int i = L[belong[l]]; i <= R[belong[l]]; i++) {
            if (a[i] > 1)
                mark[belong[l]] = 0;
        }
    }
    if (mark[belong[r]] == 0) {
        mark[belong[r]] = 1;
        for (int i = r; belong[i] == belong[r]; i--) {
            s[belong[i]] -= a[i];
            a[i] = sqrt(a[i]);
            s[belong[i]] += a[i];
        }
        for (int i = L[belong[r]]; i <= R[belong[r]]; i++) {
            if (a[i] > 1)
                mark[belong[r]] = 0;
        }
    }
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        if (mark[i] == 1)
            continue;
        s[i] = 0;
        mark[i] = 1;
        for (int j = L[i]; j <= R[i]; j++) {
            a[j] = sqrt(a[j]);
            s[i] += a[j];
            if (a[j] > 1)
                mark[i] = 0;
        }
    }
}

int query(int l, int r) {
    int ans = 0;
    if (belong[l] == belong[r]) {
        for (int i = l; i <= r; i++) {
            ans += a[i];
        }
        return ans;
    }
    for (int i = l; belong[i] == belong[l]; i++) {
        ans += a[i];
    }
    for (int i = r; belong[i] == belong[r]; i--) {
        ans += a[i];
    }
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        ans += s[i];
    }
    return ans;
}

int main() {
    while (~scanf("%d", &n)) {
        memset(mark, 0, sizeof(mark));
        memset(belong, 0, sizeof(belong));
        memset(s, 0, sizeof(s));
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        build();
        for (int i = 1; i <= n; i++) {
            int f, l, r, c;
            scanf("%d%d%d%d", &f, &l, &r, &c);
            if (f == 0) {
                update(l, r);
            } else {
                printf("%d\n", query(l, r));
            }
        }
    }
    return 0;
}

LOJ 6282 单点插入更新 单点查询

每次在 l 位置前插入 r 数值,其实这是个 rope 裸题,stl 天下第一。那既然这是个分块专题,就得用分块做。

这题的难点就是插入达到\(\sqrt{n}\)后进行重新分块,不然会超时(比如一直往这块里添加)。

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

const int maxn = 1e5 + 5;

int n;
int belong[maxn];
int a[maxn];
int block, num;
vector<int> v[maxn];
int temp[maxn << 2];
int cnt;

void build() {
    block = sqrt(n);
    num = n / block;
    if (n % block) {
        num++;
    }
    for (int i = 1; i <= n; i++) {
        belong[i] = (i - 1) / block + 1;
        v[belong[i]].push_back(a[i]);
    }
}

void re_build() {
    cnt = 0;
    int tot = 0;
    for (int i = 1; i <= num; i++) {
        for (auto it = v[i].begin(); it != v[i].end(); it++) {
            temp[tot++] = *it;
        }
        v[i].clear();
    }
    block = sqrt(tot);
    for (int i = 0; i < tot; i++) {
        v[(i - 1) / block + 1].push_back(temp[i]);
    }
    num = tot / block;
    if (tot % block)
        num++;
}

void query(int x, int &q, int &t) {
    for (int i = 1; i <= num; i++) {
        if (x > (int)v[i].size()) {
            x -= (int)v[i].size();
        } else {
            q = i;
            t = x - 1;
            return;
        }
    }
}

void update(int l, int r) {
    cnt++;
    int q = -1, t = -1;
    query(l, q, t);
    v[q].insert(v[q].begin() + t, r);
    if (cnt == block) {
        re_build();
    }
    return;
}

int main() {
    while (~scanf("%d", &n)) {
        cnt = 0;
        for (int i = 0; i <= n; i++) {
            v[i].clear();
        }
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        build();
        for (int i = 1; i <= n; i++) {
            int f, l, r, c;
            scanf("%d%d%d%d", &f, &l, &r, &c);
            if (f == 0) {
                update(l, r);
            } else {
                int q = -1, t = -1;
                query(r, q, t);
                printf("%d\n", v[q][t]);
            }
        }
    }
    return 0;
}

LOJ 6283 区间加法+乘法更新 单点查询

这题比较麻烦,但是不算难,就是写起来烦,需要多维护一个数组,乘法分配律就完事了。然后我 memset 赋 1 debug 了半小时...

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 10007;

const int maxn = 1e5 + 5;

int n;
int block, num;
ll a[maxn];
ll belong[maxn];
ll more[maxn];
ll s[maxn];
int L[maxn], R[maxn];

void build() {
    block = sqrt(n);
    num = n / block;
    if (n % block) {
        num++;
    }
    for (int i = 1; i <= num; i++) {
        L[i] = (i - 1) * block + 1;
        R[i] = i * block;
    }
    R[num] = n;
    for (int i = 1; i <= n; i++) {
        belong[i] = (i - 1) / block + 1;
    }
}

void pushup(int x) {
    for (int i = L[x]; i <= R[x]; i++) {
        a[i] = (a[i] * s[x] + more[x]) % mod;
    }
    s[x] = 1;
    more[x] = 0;
}

void update_add(int l, int r, ll c) {
    if (belong[l] == belong[r]) {
        pushup(belong[l]);
        for (int i = l; i <= r; i++) {
            a[i] = (a[i] + c) % mod;
        }
        return;
    }
    pushup(belong[l]);
    for (int i = l; belong[i] == belong[l]; i++) {
        a[i] = (a[i] + c) % mod;
    }
    pushup(belong[r]);
    for (int i = r; belong[i] == belong[r]; i--) {
        a[i] = (a[i] + c) % mod;
    }
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        more[i] = (more[i] + c) % mod;
    }
}

void update_mul(int l, int r, ll c) {
    if (belong[l] == belong[r]) {
        pushup(belong[l]);
        for (int i = l; i <= r; i++) {
            a[i] = (a[i] * c) % mod;
        }
        return;
    }
    pushup(belong[l]);
    for (int i = l; belong[i] == belong[l]; i++) {
        a[i] = (a[i] * c) % mod;
    }
    pushup(belong[r]);
    for (int i = r; belong[i] == belong[r]; i--) {
        a[i] = (a[i] * c) % mod;
    }
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        more[i] = (more[i] * c) % mod;
        s[i] = (s[i] * c) % mod;
    }
}

ll query(int x) { return a[x] * s[belong[x]] + more[belong[x]]; }

int main() {
    while (~scanf("%d", &n)) {
        for (int i = 0; i <= n; i++) {
            s[i] = 1;
        }
        memset(more, 0, sizeof(more));
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
        }
        build();
        for (int i = 1; i <= n; i++) {
            int f, l, r;
            ll c;
            scanf("%d%d%d%lld", &f, &l, &r, &c);
            if (f == 0) {
                update_add(l, r, c);
            } else if (f == 1) {
                update_mul(l, r, c);
            } else {
                printf("%lld\n", query(r) % mod);
            }
        }
    }
    return 0;
}

LOJ 6284 区间查询后修改

先查询 [l, r] 中有多少 c ,在把中间的数都改成 c 。多开一个 vis 数组,如果块中的所有数都并非都一样,则置 vis[x] = -1,此时需要强制暴力找;否则 vis 数组记录的就是整个块中的数是多少,满足条件就直接 ans += block 。

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

const int maxn = 1e5 + 5;

int belong[maxn];
int n, block, num;
int a[maxn];
int L[maxn], R[maxn];
int vis[maxn];

void build() {
    block = sqrt(n);
    num = n / block;
    if (n % block) {
        num++;
    }
    for (int i = 1; i <= num; i++) {
        L[i] = (i - 1) * block + 1;
        R[i] = i * block;
    }
    R[num] = n;
    for (int i = 1; i <= n; i++) {
        belong[i] = (i - 1) / block + 1;
    }
}

void pushup(int x) {
    if (vis[x] == -1)
        return;
    for (int i = L[x]; i <= R[x]; i++) {
        a[i] = vis[x];
    }
    vis[x] = -1;
}

int query(int l, int r, int c) {
    int ans = 0;
    if (belong[l] == belong[r]) {
        pushup(belong[l]);
        for (int i = l; i <= r; i++) {
            if (a[i] == c) {
                ans++;
            }
            a[i] = c;
        }
        return ans;
    }
    pushup(belong[l]);
    for (int i = l; belong[i] == belong[l]; i++) {
        if (a[i] == c) {
            ans++;
        }
        a[i] = c;
    }
    pushup(belong[r]);
    for (int i = r; belong[i] == belong[r]; i--) {
        if (a[i] == c) {
            ans++;
        }
        a[i] = c;
    }
    for (int i = belong[l] + 1; i <= belong[r] - 1; i++) {
        if (vis[i] == -1) {
            for (int j = L[i]; j <= R[i]; j++) {
                if (a[j] == c) {
                    ans++;
                }
            }
        } else {
            if (vis[i] == c) {
                ans += block;
            }
        }
        vis[i] = c;
    }
    return ans;
}

int main() {
    while (~scanf("%d", &n)) {
        memset(belong, 0, sizeof(belong));
        memset(vis, -1, sizeof(vis));
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        build();
        for (int i = 1; i <= n; i++) {
            int l, r, c;
            scanf("%d%d%d", &l, &r, &c);
            printf("%d\n", query(l, r, c));
        }
    }
    return 0;
}

LOJ 6285 区间查询众数

这题...就很麻烦了,需要先预处理出每个块内的众数,然后再用 upper_bound - lower_bound 去得到某个数的个数。总之说起来挺复杂的,看着代码理解一下还是可以的。

吐槽一下讨论版玄学,这啥数据啊,块的大小还得是 30 ,我代码都重构的不成样子了...

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

const int maxn = 1e5 + 5;

int n;
int block, num;
int belong[maxn];
int a[maxn];
map<int, int> mp;                // a[i] 是第几个出现的
int val[maxn];                   // val[id] = a[i]
int mark[maxn / 30][maxn / 30];  // 预处理每个整块的众数
int cnt[maxn];
vector<int> v[maxn];  // 记录每个数出现的每一个位置

/*void build() {
}*/

inline int get_id(int l, int r, int x) {
    return upper_bound(v[x].begin(), v[x].end(), r) - lower_bound(v[x].begin(), v[x].end(), l);
}

inline int query(int l, int r) {
    int MAX = 0, tot = 0;
    if (belong[l] == belong[r]) {
        for (int i = l; i <= r; i++) {
            int temp = get_id(l, r, a[i]);
            if (temp > tot || (temp == tot && val[a[i]] < val[MAX])) {
                tot = temp;
                MAX = a[i];
            }
        }
        return MAX;
    }
    for (int i = l; belong[i] == belong[l]; i++) {
        int temp = get_id(l, r, a[i]);
        if (temp > tot || (temp == tot && val[a[i]] < val[MAX])) {
            tot = temp;
            MAX = a[i];
        }
    }
    for (int i = r; belong[i] == belong[r]; i--) {
        int temp = get_id(l, r, a[i]);
        if (temp > tot || (temp == tot && val[a[i]] < val[MAX])) {
            tot = temp;
            MAX = a[i];
        }
    }
    int res = mark[belong[l] + 1][belong[r] - 1];
    int temp = get_id(l, r, res);
    if (temp > tot || (temp == tot && val[res] < val[MAX])) {
        tot = temp;
        MAX = res;
    }
    return MAX;
}

int main() {
    scanf("%d", &n);
    int id = 0;
    block = 30;
    num = n / block;
    if (n % block) {
        num++;
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        if (mp[a[i]] == 0) {
            mp[a[i]] = ++id;
            val[id] = a[i];
        }
        belong[i] = (i - 1) / block + 1;
        a[i] = mp[a[i]];
        v[a[i]].push_back(i);
    }
    for (int i = 1; i <= num; i++) {
        memset(cnt, 0, sizeof(cnt));
        int MAX = 0, tot = 0;
        for (int j = (i - 1) * block + 1; j <= n; j++) {
            int temp = ++cnt[a[j]];
            if (temp > tot || (temp == tot && val[a[j]] < val[MAX])) {
                tot = temp;
                MAX = a[j];
            }
            mark[i][belong[j]] = MAX;
        }
    }
    for (int i = 1; i <= n; i++) {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", val[query(l, r)]);
    }
    return 0;
}

总结一下分块,那就是暴力哇,惹不起惹不起.jpg,溜了溜了。

原文地址:https://www.cnblogs.com/Decray/p/10924593.html

时间: 2024-10-31 03:01:23

数列分块入门1-9 LibreOJ的相关文章

loj 6278 6279 数列分块入门 2 3

参考:「分块」数列分块入门1 – 9 by hzwer 2 Description 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,询问区间内小于某个值\(x\)的元素个数. 思路 每个块内保持升序排列. 则块外暴力统计,块内二分查找分界点. 一些注意点,如: 要记录下标: 块外暴力修改完之后需要再排序: 在块内二分查找的值是\(c-tag[i]\)而非\(c\). Code #include <bits/stdc++.h> #define maxn 50010 #def

loj 6277 6280 数列分块入门 1 4

参考:「分块」数列分块入门1 – 9 by hzwer 1 Description 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,单点查值. 思路 用\(tag\)记录每个块整体的增量. Code #include <bits/stdc++.h> #define maxn 50010 #define F(i, a, b) for (int i = (a); i < (b); ++i) #define F2(i, a, b) for (int i = (a); i

LOJ#6284. 数列分块入门 8

#6284. 数列分块入门 8 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 1 测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间询问等于一个数 ccc 的元素,并将这个区间的所有元素改为 ccc. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入三个数字 ll

LOJ6277~6285 数列分块入门

Portals 分块需注意的问题 数组大小应为\(N+\sqrt N\),因为最后一个块可能会超出\(N\)的范围.改成记录\(blk,fr,to\)就不用担心这个了 当操作的区间在一个块内时,要特判成暴力修改. 要清楚什么时候应该+tag[t] 最后一个块是越界的,注意是否有影响 数列分块入门 1 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,单点查值. //数列分块入门 1 #include <cstdio> #include <cmath> inlin

数列分块入门

分块是 莫队 算法的前置知识,也是一种十分 暴力 的数据结构. 分块的核心思想是把要操作的数列 \(a_i\) 分成若干长度相等的"块":修改/查询时对于整一块都在指定区间 \([L,R]\) 内的块整体修改/查询,对于只有块的一部分在指定区间内的暴力修改/查询. 由于不需要操作/查询具有 区间加法 等性质,分块比线段树.树状数组.ST表等数据结构具有更加灵活的应用. 先来看一道例题 数列分块入门 4,简而言之,就是要求实现区间加法&区间查询:线段树可以很轻松地实现这两个操作,

数列分块入门5 解题报告

占坑QAQ 数列分块系列目录 数列分块入门1 数列分块入门2 数列分块入门3 数列分块入门4 数列分块入门5 <- 数列分块入门6 数列分块入门7 数列分块入门8 数列分块入门9 蒲公英 公主的朋友 原文地址:https://www.cnblogs.com/louhancheng/p/10051160.html

数列分块入门2 解题报告

题意概括 区间加法,区间询问小于一个数的个数. 正题 对于每个块,除原数组之外用一个vector来有序地存储所有数.当区间加时,对于每个完整块维护共同加数,对于不完整的块直接暴力加上再重新排序.当询问时,对于每个完整块在vector中二分,对于不完整的,直接暴力计数. 代码 #include<cstdio> #include<vector> #include<algorithm> #include<cmath> using namespace std; #d

LibreOJ6279. 数列分块入门 3 题解

题目链接:https://loj.ac/problem/6279 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的前驱(比其小的最大元素). 输入格式 第一行输入一个数字 \(n\). 第二行输入 \(n\) 个数字,第 \(i\) 个数字为 \(a_i\),以空格隔开. 接下来输入 \(n\) 行询问,每行输入四个数字 \(opt\).\(l\).\(r\).\(c\),以空格隔开. 若 \(opt=0\),表示将位于

Loj 6279. 数列分块入门 3

题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,询问区间内小于某个值 xxx 的前驱(比其小的最大元素). 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 iii 个数字为 aia_iai?,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若 opt=0\mathrm{opt} = 0opt=0,表示将位于 [l,r][l, r][l,r] 的之间的数字