Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【算法竞赛】分块入门九题题解

【算法竞赛】分块入门九题题解

作者头像
Livinfly
发布于 2023-05-16 12:23:26
发布于 2023-05-16 12:23:26
70000
代码可运行
举报
文章被收录于专栏:LivinflyLivinfly
运行总次数:0
代码可运行

分块入门九题

code by Livinfly

原文连接:「分块」数列分块入门1 – 9 by hzwer - 分块 - hzwer.com

开始前,先%%hzwer大佬

主要是贴我的代码,和发现的一些问题,主要思路的讲解hzwer学长已经讲得非常深入浅出了!

关于一些块的大小的取法,数列分块总结——题目总版(hzwer分块九题及其他题目)(分块) - Flash_Hu - 博客园 (cnblogs.com)有提到一些,我这里就全方便起见取\sqrt{n}了。

分块入门九题的题目:题库 - LibreOJ (loj.ac)

我在LOJ上提交都有记录,用户名为Livinfly,如有需要也可以去LOJ查看通过记录。

分块1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, addTag;

void Add(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    if(bl == br) {
        for(int i = l; i <= r; i ++)
            a[i] += c;
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            addTag[i] += c;
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            a[i] += c;
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            a[i] += c;
        }
    }
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize+1;
    a.resize(n+1), belong.resize(n+1), addTag.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
    }
    while(n --) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0) {
            Add(l, r, c);
        }
        else {
            cout << a[r] + addTag[belong[r]] << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, addTag;
vector<vector<int>> va;

void Resort(int x) {
    va[x].clear();
    for(int i = (x-1)*bSize+1; i <= n && belong[i] == x; i ++) {
        va[x].push_back(a[i]);
    }
    sort(all(va[x]));
}
void Add(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            a[i] += c;
        }
        Resort(bl);
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            addTag[i] += c;
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            a[i] += c;
        }
        Resort(bl);
        for(int i = r; i > 0 && belong[i] == br; i --) {
            a[i] += c;
        }
        Resort(br);
    }
}
int Query(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    int ret = 0;
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            if(a[i]+addTag[bl] < c) {
                ret ++;
            }
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            int t = c-addTag[i];
            ret += (lower_bound(all(va[i]), t) - va[i].begin());
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            if(a[i]+addTag[bl] < c) {
                ret ++;
            }
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            if(a[i]+addTag[br] < c) {
                ret ++;
            }
        }
    }
    return ret;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize+1;
    a.resize(n+1), va.resize(bNum+1), belong.resize(n+1), addTag.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize+1;
        va[belong[i]].push_back(a[i]);
    }
    for(int i = 1; i <= bNum; i ++) 
        sort(all(va[i]));
    for(int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0) {
            Add(l, r, c);
        }
        else {
            cout << Query(l, r, c*c) << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("a2.in", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块3

这道题数据稍微弱了点,然后hzwer学长的std也假了,但是还是%%

std用seterase会一次把所有的值删掉,但我们其实只删一个。

考虑用multiset,注意不要直接erase,这样也是全部一次删完,要find出来,删指针,才能删一个!

然后,时间复杂度做法1比假的set做法后面的点每个平均快100ms,multiset的时间更不忍直视((

没有特别想清楚为什么qwq

留坑,如果有人知道的,可以email or qq教教我

做法1,同分块2的自己sort保证有序的性质

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, addTag;
vector<vector<int>> va;

void Resort(int x) {
    va[x].clear();
    for(int i = (x-1)*bSize+1; i <= n && belong[i] == x; i ++) {
        va[x].push_back(a[i]);
    }
    sort(all(va[x]));
}
void Add(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            a[i] += c;
        }
        Resort(bl);
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            addTag[i] += c;
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            a[i] += c;
        }
        Resort(bl);
        for(int i = r; i > 0 && belong[i] == br; i --) {
            a[i] += c;
        }
        Resort(br);
    }
}
int Query(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    int ret = -1;
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            if(a[i]+addTag[bl] < c) {
                ret = max(ret, a[i]+addTag[bl]);
            }
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            int t = c-addTag[i];
            auto iter = lower_bound(all(va[i]), t);
            if(iter != va[i].begin()) {
                // + addTag[i]
                ret = max(ret, *(-- iter) + addTag[i]);
            }
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            if(a[i]+addTag[bl] < c) {
                ret = max(ret, a[i]+addTag[bl]);
            }
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            if(a[i]+addTag[br] < c) {
                ret = max(ret, a[i]+addTag[br]);
            }
        }
    }
    return ret;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize+1;
    a.resize(n+1), va.resize(bNum+1), belong.resize(n+1), addTag.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize+1;
        va[belong[i]].push_back(a[i]);
    }
    for(int i = 1; i <= bNum; i ++) 
        sort(all(va[i]));
    for(int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0) {
            Add(l, r, c);
        }
        else {
            cout << Query(l, r, c) << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("a2.in", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

做法2,multiset

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, addTag;
vector<multiset<int>> va;

void Add(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            va[bl].erase(va[bl].find(a[i]));
            a[i] += c;
            va[bl].insert(a[i]);
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            addTag[i] += c;
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            va[bl].erase(va[bl].find(a[i]));
            a[i] += c;
            va[bl].insert(a[i]);
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            va[br].erase(va[br].find(a[i]));
            a[i] += c;
            va[br].insert(a[i]);
        }
    }
}
int Query(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    int ret = -1;
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            if(a[i]+addTag[bl] < c) {
                ret = max(ret, a[i]+addTag[bl]);
            }
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            int t = c-addTag[i];
            auto iter = va[i].lower_bound(t);
            if(iter != va[i].begin()) {
                // + addTag[i]
                ret = max(ret, *(-- iter) + addTag[i]);
            }
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            if(a[i]+addTag[bl] < c) {
                ret = max(ret, a[i]+addTag[bl]);
            }
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            if(a[i]+addTag[br] < c) {
                ret = max(ret, a[i]+addTag[br]);
            }
        }
    }
    return ret;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize+1;
    a.resize(n+1), va.resize(bNum+1), belong.resize(n+1), addTag.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize+1;
        va[(i-1)/bSize+1].insert(a[i]);
    }
    for(int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0) {
            Add(l, r, c);
        }
        else {
            cout << Query(l, r, c) << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("a2.in", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块4

注意开long long吧,我是直接过程转化了,看起来可能比较难看(逃

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, addTag, sum;

void Add(int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            a[i] += c;
            sum[bl] += c;
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            addTag[i] += c;
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            a[i] += c;
            sum[bl] += c;
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            a[i] += c;
            sum[br] += c;
        }
    }
}
int Query(int l, int r, const int &MO) {
    int bl = belong[l], br = belong[r];
    int ret = 0;
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            int x = (1LL*a[i] + addTag[bl]) % MO;
            ret = (1LL*ret + x) % MO;
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            int x = (1LL*sum[i] + 1LL*addTag[i]*bSize%MO) % MO;
            ret = (1LL*ret + x) % MO;
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            int x = (1LL*a[i] + addTag[bl]) % MO;
            ret = (1LL*ret + x) % MO;
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            int x = (1LL*a[i] + addTag[br]) % MO;
            ret = (1LL*ret + x) % MO;
        }
    }
    return ret;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), addTag.resize(bNum+1), sum.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
        sum[belong[i]] += a[i];
    }
    for(int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0) {
            Add(l, r, c);
        }
        else {
            int MO = c+1;
            cout << (Query(l, r, c+1)%MO+MO) % MO << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块5

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, sum;
vector<bool> done;

void Modify(int l, int r) {
    int bl = belong[l], br = belong[r];
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            sum[bl] -= a[i];
            a[i] = sqrt(a[i]);
            sum[bl] += a[i];
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            if(done[i]) continue;
            done[i] = true;
            // 和n要取较小的值,循环里面i和j不要想错了qwq
            for(int j = (i-1)*bSize + 1; j <= min(i*bSize, n); j ++) {
                sum[i] -= a[j];
                a[j] = sqrt(a[j]);
                sum[i] += a[j];
                if(a[j] > 1) done[i] = false;
            }
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            sum[bl] -= a[i];
            a[i] = sqrt(a[i]);
            sum[bl] += a[i];
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            sum[br] -= a[i];
            a[i] = sqrt(a[i]);
            sum[br] += a[i];
        }
    }
}
int Query(int l, int r) {
    int bl = belong[l], br = belong[r];
    int ret = 0;
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            ret += a[i];
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            ret += sum[i];
        }
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            ret += a[i];
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            ret += a[i];
        }
    }
    return ret;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), done.resize(bNum+1), sum.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
        sum[belong[i]] += a[i];
    }
    for(int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0) {
            Modify(l, r);
        }
        else {
            cout << Query(l, r) << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块6

因为是随机数据,重新分块(重构)的代码注释掉也是可以过的。

不重新分块625ms,hzwer学长提到的每\sqrt{n}次重构一次,是391ms,std里的看起来挺玄学的重构条件是196ms,分块真是玄学(逃

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong;
vector<vector<int>> va;

PII Find(int x) {
    int ret = 1;
    while(x > va[ret].size()) {
        x -= va[ret].size();
        ret ++;
    }
    return {ret, x-1};
}
void Rebuild() {
    a.assign(1, 0);
    for(int i = 1; i <= bNum; i ++) {
        a.insert(a.end(), va[i].begin(), va[i].end());
        va[i].clear();
    }
    n = a.size()-1;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    // 理论上只要更新bSize和va,但为了一致性,这里还是都更新了
    belong.resize(n+1), va.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        belong[i] = (i-1)/bSize + 1;
        va[belong[i]].push_back(a[i]);
    }
}
void Insert(int x, int c) {
    auto [i, b] = Find(x);
    va[i].insert(va[i].begin() + b, c);
    // if(va[i].size() > 20*bSize) {
    //     Rebuild();
    // }
}
int Query(int x) {
    auto [i, b] = Find(x);
    return va[i][b];
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), va.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
        va[belong[i]].push_back(a[i]);
    }
    int t = sqrt(n);
    // 由于n在重新分块时更新了,所以,这里循环询问的n要存到别的变量里面
    int nn = n;
    for(int i = 0; i < nn; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 0) {
            Insert(l, r);
            // if(i % t == 0) {
            //     Rebuild();
            // }
        }
        else {
            cout << Query(r) << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块7

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int MO = 10007;

int n, bSize, bNum;
vector<int> a, belong, addTag, mulTag;

void Reset(int x) {
    for(int i = (x-1)*bSize+1; i <= min(n, x*bSize); i ++)
        a[i] = (1LL*a[i]*mulTag[x] % MO + addTag[x]) % MO;
    mulTag[x] = 1, addTag[x] = 0;
}
void Modify(int op, int l, int r, int c) {
    int bl = belong[l], br = belong[r];
    if(bl == br) {
        Reset(bl);
        for(int i = l; i <= r; i ++) {
            if(op == 0) {
                a[i] = (1LL*a[i] + c) % MO;
            }
            else {
                a[i] = 1LL*a[i]*c % MO;
            }
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            if(op == 0) {
                addTag[i] = (1LL*addTag[i] + c) % MO;
            }
            else {
                addTag[i] = 1LL*addTag[i] * c % MO;
                mulTag[i] = 1LL*mulTag[i] * c % MO;
            }
        }
        Reset(bl);
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            if(op == 0) {
                a[i] = (1LL*a[i] + c) % MO;
            }
            else {
                a[i] = 1LL*a[i]*c % MO;
            }
        }
        Reset(br);
        for(int i = r; i > 0 && belong[i] == br; i --) {
            if(op == 0) {
                a[i] = (1LL*a[i] + c) % MO;
            }
            else {
                a[i] = 1LL*a[i]*c % MO;
            }
        }
    }
}
int Query(int x) {
    int bx = belong[x];
    return (1LL*a[x] * mulTag[bx] % MO + addTag[bx]) % MO;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), addTag.resize(bNum+1), mulTag.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
    }
    for(int i = 1; i <= bNum; i ++) {
        mulTag[i] = 1;
    }
    for(int i = 0; i < n; i ++) {
        int op, l, r, c;
        cin >> op >> l >> r >> c;
        if(op == 2) {
            cout << Query(r) << '\n';
        }
        else {
            Modify(op, l, r, c);
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块8

需要去分析分块的时间复杂度,然后大胆分块暴力。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, tag;

void Reset(int x) {
    if(tag[x] == -1) return;
    for(int i = (x-1)*bSize + 1; i <= min(n, x*bSize); i ++) {
        a[i] = tag[x];
    }
    tag[x] = -1;
}
int Query(int l, int r, int c) {
    int bl = belong[l], br = belong[r], ret = 0;
    if(bl == br) {
        Reset(bl);
        for(int i = l; i <= r; i ++) {
            if(a[i] == c) {
                ret ++;
            }
            else {
                a[i] = c;
            }
        }
    }
    else {
        for(int i = bl+1; i < br; i ++) {
            if(tag[i] == c) {
                ret += bSize;
            }
            else if(tag[i] == -1) {
                // i和j分清楚。。
                for(int j = (i-1)*bSize + 1; j <= min(n, i*bSize); j ++) {
                    if(a[j] == c) {
                        ret ++;
                    }
                }
            }
            tag[i] = c;
        }
        Reset(bl);
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            if(a[i] == c) {
                ret ++;
            }
            else {
                a[i] = c;
            }
        }
        Reset(br);
        for(int i = r; i > 0 && belong[i] == br; i --) {
            if(a[i] == c) {
                ret ++;
            }
            else {
                a[i] = c;
            }
        }
    }
    return ret;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), tag.assign(bNum+1, -1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
    }
    for(int i = 0; i < n; i ++) {
        int l, r, c;
        cin >> l >> r >> c;
        cout << Query(l, r, c) << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

分块9

好多做法,都不会(

做法1 - 分块 - 预处理块区间

很容易可以判断,[L, R]的区间众数,一定是在[L, R]中一段连续的整块的众数和两边非完整块的数的并集内。

然后,我们就可以处理f[i, j]表示第 i 块到第 j 块区间的区间众数,不难发现,预处理的时间复杂度为O(n \cdot 块数) ,是可以接受的,这实在是太神奇了!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

int n, bSize, bNum;
vector<int> a, belong, cnt, val;
int nid;
map<int, int> mp;
vector<vector<int>> va, f;

void PrevCalc() {
    for(int i = 1; i <= bNum; i ++) {
        int mx = 0, res = 0;
        cnt.assign(n+1, 0);
        for(int j = (i-1)*bSize + 1; j <= n; j ++) {
            int bj = belong[j];
            cnt[a[j]] ++;
            if(cnt[a[j]] > mx || cnt[a[j]] == mx && val[a[j]] < val[res])
                mx = cnt[a[j]], res = a[j];
            f[i][bj] = res;
        }
    }
}
int Query(int l, int r, int c) {
    return (upper_bound(all(va[c]), r) - lower_bound(all(va[c]), l));
}
int Query(int l, int r) {
    int bl = belong[l], br = belong[r], ret = 0, mx = 0;
    if(bl == br) {
        for(int i = l; i <= r; i ++) {
            int t = Query(l, r, a[i]);
            if(t > mx || t == mx && val[a[i]] < val[ret]) {
                mx = t, ret = a[i];
            }
        }
    }
    else {
        ret = f[bl+1][br-1], mx = Query(l, r, ret);
        for(int i = l; i <= n && belong[i] == bl; i ++) {
            int t = Query(l, r, a[i]);
            if(t > mx || t == mx && val[a[i]] < val[ret]) {
                mx = t, ret = a[i];
            }
        }
        for(int i = r; i > 0 && belong[i] == br; i --) {
            int t = Query(l, r, a[i]);
            if(t > mx || t == mx && val[a[i]] < val[ret]) {
                mx = t, ret = a[i];
            }
        }
    }
    return val[ret];
}
void solve() {
    cin >> n;
    bSize = sqrt(n/(log(n)/log(2.0))), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), val.resize(n+1), va.resize(n+1), f.resize(bNum+1);
    for(auto &v : f) 
        v.resize(bNum+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
        if(!mp.count(a[i])) {
            mp[a[i]] = ++ nid;
            val[nid] = a[i];
        }
        a[i] = mp[a[i]];
        va[a[i]].push_back(i);
    }
    PrevCalc();
    int ans = 0;
    for(int i = 0; i < n; i ++) {
        int l, r;
        cin >> l >> r;
        // l = (l+ans-1) % n + 1, r = (r+ans-1) % n + 1;;
        if(l > r) swap(l, r);
        ans = Query(l, r);
        cout << ans << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

做法2 - 普通莫队 + 值域分块

数列分块入门 #9 莫队做法 - 316.2277 - 洛谷博客 (luogu.com.cn)

如果只考虑众数出现的次数,直接普通莫队维护x出现的次数出现了x次的数有多少个就可以解决。

但现在需要输出具体的最小的数,可以用(次数)值域分块来找,用普通莫队维护f[i, j],表示在第 i 个值块中恰出现 j 次的值的个数(和参考博客参数顺序不同),关于为什么是个数的话,还是为了在维护这个信息时,更加方便,其实只是为了判断是否存在恰好为 j 次的。

普通莫队维护了信息,一次查询需要O(\sqrt{n})

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

struct Rec {
    int l, r, qid;
};
int n, bSize, bNum, modecnt;
vector<int> a, belong, val, cnt, ccnt;
vector<vector<int>> f;
vector<Rec> query;

void add(int x) {
    x = a[x];
    int bx = belong[x], &c = cnt[x];
    ccnt[c] --;
    f[bx][c] --;
    c ++;
    if(modecnt < c) {
        modecnt = c;
    }
    ccnt[c] ++;
    f[bx][c] ++;
}
void del(int x) {
    x = a[x];
    int bx = belong[x], &c = cnt[x];
    ccnt[c] --;
    f[bx][c] --;
    if(modecnt == c && ccnt[c] == 0) {
        modecnt --;
    }
    c --;
    ccnt[c] ++;
    f[bx][c] ++;
}
int Query() {
    for(int i = 1; i <= bNum; i ++) {
        if(f[i][modecnt] > 0) {
            for(int j = (i-1)*bSize + 1; j <= min(i*bSize, n); j ++) {
                if(cnt[j] == modecnt) {
                    return val[j];
                }
            }
        }
    }
    return -1;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), val.resize(n+1), cnt.resize(n+1);
    ccnt.resize(n+1), query.resize(n), f.resize(bNum+1);
    for(auto &v : f) v.resize(n+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
        val[i] = a[i];
    }
    sort(1+all(val));
    val.resize(unique(1+all(val)) - val.begin());
    for(int i = 1; i <= n; i ++) {
        a[i] = lower_bound(1+all(val), a[i]) - val.begin();
    }
    for(int i = 0; i < n; i ++) {
        auto &[l, r, qid] = query[i];
        cin >> l >> r;
        qid = i;
    }
    sort(all(query), [&](const Rec &a, const Rec &b) {
        int abl = belong[a.l], bbl = belong[b.l];
        if(abl != bbl) {
            return abl < bbl;
        }
        else {
            if(abl & 1) return a.r < b.r;
            else return a.r > b.r;
        }
    });
    vector<int> ans(n);
    int l = 1, r = 0;
    for(int i = 0; i < n; i ++) {
        auto [ll, rr, qid] = query[i];
        while(l > ll) add(-- l);
        while(r < rr) add(++ r);
        while(l < ll) del(l ++);
        while(r > rr) del(r --);
        ans[qid] = Query();
    }
    for(auto x : ans) {
        cout << x << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}

做法3 - 回滚莫队

不删除莫队,状态/信息正常回滚,答案记录跳回。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma GCC optimize(2)

#include <bits/stdc++.h>

#define fi first
#define se second
#define mkp(x, y) make_pair((x), (y))
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

struct Rec {
    int l, r, qid;
};
int n, bSize, bNum, modecnt, modecntB, res, resB;
vector<int> a, belong, val, cnt, tcnt;
vector<Rec> query;

int bf(int l, int r) {
    int ret = 0, mx = 0;
    tcnt.assign(n+1, 0);
    for(int i = l; i <= r; i ++) { // tcnt
        tcnt[a[i]] ++;
        if(tcnt[a[i]] > mx || tcnt[a[i]] == mx && a[i] < ret) {
            mx = tcnt[a[i]], ret = a[i];
        }
    }
    return val[ret];
}
void add(int x) {
    x = a[x];
    cnt[x] ++;
    if(cnt[x] > modecnt || cnt[x] == modecnt && x < res) {
        modecnt = cnt[x], res = x;
    }
}
void del(int x) {
    x = a[x];
    cnt[x] --;
}
void solve() {
    cin >> n;
    bSize = sqrt(n), bNum = (n-1)/bSize + 1;
    a.resize(n+1), belong.resize(n+1), val.resize(n+1);
    cnt.resize(n+1);
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        belong[i] = (i-1)/bSize + 1;
        val[i] = a[i];
    }
    sort(1+all(val));
    val.resize(unique(1+all(val)) - val.begin());
    for(int i = 1; i <= n; i ++) {
        a[i] = lower_bound(1+all(val), a[i]) - val.begin();
    }
    query.resize(n);
    n = 0;
    for(auto &[l, r, qid] : query) {
        cin >> l >> r;
        qid = n ++;
    }
    sort(all(query), [&](const Rec &a, const Rec &b) {
        int abl = belong[a.l], bbl = belong[b.l];
        return abl == bbl ? a.r < b.r : abl < bbl;
    });

    vector<int> ans(n);
    for(int bid = 1, id = 0; bid <= bNum; bid ++) {
        int tp = min(bid*bSize, n), l = tp+1, r = tp;
        res = modecnt = 0;
        cnt.assign(n+1, 0);
        for( ; id < n && belong[query[id].l] == bid; id ++) {
            auto [ll, rr, qid] = query[id];
            int bll = belong[ll], brr = belong[rr];
            if(bll == brr) {
                ans[qid] = bf(ll, rr);
            }
            else {
                while(r < rr) add(++ r);
                modecntB = modecnt, resB = res;
                while(l > ll) add(-- l);
                ans[qid] = val[res];
                while(l < tp+1) del(l ++);
                modecnt = modecntB, res = resB;
            }
        }
    }
    for(auto x : ans) {
        cout << x << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed;  // << setprecision(20); // double
    // freopen("i.txt", "r", stdin);
    // freopen("o.txt", "w", stdout);
    // time_t t1 = clock();
    int Tcase = 1;
    // cin >> Tcase; // scanf("%d", &Tcase);
    while (Tcase--) 
        solve();
    // cout << "time: " << 1000.0 * ((clock() - t1) / CLOCKS_PER_SEC) << "ms\n";
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023年05月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【算法竞赛】Namomo Winter 2023 Day 3 Div 2
Dashboard - 2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest - Codeforces
Livinfly
2023/01/11
3610
IME++ Starters Try-outs 2019 题解
显然如果有多棵树,则一定会存在无法到达的点。否则直接暴力 b f s bfs bfs求每个点到其余点的距离, a n s ans ans取 m a x max max即可
dejavu1zz
2020/12/02
6060
IME++ Starters Try-outs 2019 题解
「CSP-J/S2022模拟赛7.12 D」来 / YbtOJ 「分块算法」历史序列
分块,每块内维护其排序,对于整块的 2 操作直接丢到一个递增的 vector 里,Pushdown 时双指针扫描即可。
yzxoi
2022/09/19
3140
AtCoder Beginner Contest 185 (手速场)
直接算C ( l − 1 , l − 12 )即可。由于题目中没有模数,偷懒使用了JAVA的大整数
dejavu1zz
2020/12/16
3300
AtCoder Beginner Contest 185 (手速场)
BZOJ2388: 旅行规划(分块 凸包)
题意 题目链接 Sol 直接挂队爷的题解了 分块题好难调啊qwq #include<bits/stdc++.h> #define LL long long using namespace std;
attack
2019/01/30
4450
洛谷P4462 [CQOI2018]异或序列(莫队)
题意 题目链接 Sol 一开始以为K每次都是给出的想了半天不会做。 然而发现读错题了维护个前缀异或和然后直接莫队搞就行,。 #include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define fi first #define se second //#define int long long #define LL long long #define Fin(x) {freopen(#x
attack
2019/03/15
3260
2020年第一届辽宁省大学生程序设计竞赛
可以使用一个 p a i r pair pair数组来保存< i n t , s t r i n g int,string int,string>对,排序后按题意模拟即可。注意输出队员姓名的顺序是按照排名从大到小排列,并且要开 3 3 3倍 n n n的空间。
dejavu1zz
2020/11/24
5850
2020年第一届辽宁省大学生程序设计竞赛
BZOJ2956: 模积和(数论分块)
把所有的都展开,直接分块。关键是那个\(i \not= j\)的地方需要减。。。。
attack
2019/03/04
5250
LuoguP5356 [Ynoi2017] 由乃打扑克
1\leq n,m\leq 10^5,-2\times 10^4\leq 每次加上的数和原序列的数 \leq 2\times 10^4。
yzxoi
2022/09/19
2570
Codeforces 的题目真的值得算法竞赛选手训练吗?
个串,有两种操作,一种是给某个串加一个字符,另一种是求存不存在一个串是查询串的子串。强制在线。
ACM算法日常
2021/11/10
9630
loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)
考虑K比较小的情况,可以直接暴力建SAM, 枚举w的子串算出现次数。询问用个 的vector记录一下每次在vector里二分就好。
attack
2019/03/19
6520
洛谷P3247 [HNOI2016]最小公倍数(分块 带撤销加权并查集)
给出一张带权无向图,每次询问\((u, v)\)之间是否存在一条路径满足\(max(a) = A, max(b) = B\)
attack
2019/03/15
4070
P6774 [NOI2020] 时代的眼泪
给定长度为 n 的序列,其中第 i 个点的权值为 p_i,保证 p_i 为 [1,n] 的排列。
yzxoi
2022/09/19
3000
第三届“传智杯”全国大学生IT技能大赛(初赛A组)题解
显然,数组中的每一对数都有两种情况:1.异或之后二进制位仅有1位为1,2.有多位唯一。
attack
2020/12/22
9520
第三届“传智杯”全国大学生IT技能大赛(初赛A组)题解
YbtOJ 774「分块算法」奇妙的树
假设 i 号点的父节点为 f_i(方便起见认为 f_1=0),小 A 发现这棵树非常奇妙,它满足一个特殊的性质:对于任意整数 i\in[2,n],满足 f_{i-1}\le f_i < i
yzxoi
2022/09/19
4520
树状数组求逆序对以及相关例题
求逆序对有两种方法:归并排序和树状数组,但是归并排序求得的逆序对是总共的逆序对数量,有些时候我们需要求得某个数后面的逆序对数量或者某个数前面的逆序对数量。
dejavu1zz
2020/11/12
6160
树状数组求逆序对以及相关例题
codeforces 1407C(数学+交互题)
如果一个大数余去一个小数,则余数肯定小于小数。如果小数余去大数,则余数仍是小数。 根据这个性质,我们可以通过2n-1次询问来确定除最大值以外的数的位置。而最大值我们可以通过扫一遍数组来确定。
dejavu1zz
2020/10/23
4040
codeforces 1407C(数学+交互题)
bzoj3217 ALOEXT
这道题显然可以用替罪羊树套 Trie 解决,但是对于不会替罪羊树的选手(比如我)就可以选择块状链表+Trie。
yzxoi
2022/09/19
2570
Codeforces Round #677 (Div. 3)
显然,如果最大值和最小值相同,则肯定不满足题意。否则,一定存在一个值mx,它的左右两边存在一个小于它的数。此时,该位置的鱼满足题意。
dejavu1zz
2020/10/21
5760
Codeforces Round #677 (Div. 3)
YbtOJ 772「分块算法」密码破译
你有一个 n 列,无穷行的表格,每个格子上都有一个正整数,第 i 行第 j 列的数为 a_{i,j}。我们通过如下方法来构造这个表格:
yzxoi
2022/09/19
7630
相关推荐
【算法竞赛】Namomo Winter 2023 Day 3 Div 2
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验