[数据结构]分块专题

洛谷 – P3870 – [TJOI2009]开关
https://www.luogu.org/problem/P3870
这次写的就很漂亮了啊。
注意一下,num是所在块的编号,便于维护整块信息(小心多定义冲突)。
L数组和R数组是保存了单个位置的左右端点,不是每块的左右端点。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10, mod = 1e9 + 7;
int a[maxn], fan[maxn], tag[maxn], L[maxn], R[maxn], sqn;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    int n, q;
    cin >> n >> q;
    sqn = sqrt(n);
    //记录每个点所在块的左右端点
    int tl = 1, tr = 1 + sqn - 1;
    for (int i = 1; i <= n; ++i){
        L[i] = tl, R[i] = min(tr, n);
        if (i % sqn == 0) tl += sqn, tr += sqn;
    }

    int p, l, r;
    while (q--){
        cin >> p >> l >> r;
        if (p == 0){
            for (int i = l; i <= r; ++i){
                int num = (i + sqn - 1) / sqn;
                if (i == L[i] && i + sqn - 1 <= r){
                    fan[num] ^= 1;
                    tag[num] = R[i] - L[i] + 1 - tag[num];
                    i += sqn - 1;
                }else{
                    a[i] ^= 1;
                    if ((a[i] ^ fan[num]) == 1) ++tag[num];
                    else --tag[num];
                }
            }
        }else{
            int ans = 0;
            for (int i = l; i <= r; ++i){
                int num = (i + sqn - 1) / sqn;
                if (i == L[i] && i + sqn - 1 <= r){
                    ans += tag[num];
                    i += sqn - 1;
                }else{
                    if ((a[i] ^ fan[num]) == 1) ++ans;
                }
            }
            cout << ans << '\n';
        }
    }
    return 0;
}

洛谷 – P2801 – 教主的魔法
https://www.luogu.org/problem/P2801
数据水警告!这题数据特别水。
这是我第一次写的分块写的特别丑,之后写上面这题的时候优化了很多语句和结构,应该就是最终的模板了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10, mod = 1e9 + 7;
int a[maxn], kuai[maxn], tag[1010], L[1010], R[1010], sqn;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    int n, q;
    cin >> n >> q;
    sqn = sqrt(n);
    for (int i = 1; i <= n; ++i){
        cin >> a[i];
        kuai[i] = a[i];
    }
    int num = 1;
    for (int i = 1; 1; i += sqn){
        if (i + sqn > n){
            L[num] = i, R[num] = n + 1;
            sort(kuai + i, kuai + 1 + n);
            break;
        }
        L[num] = i, R[num] = i + sqn;
        sort(kuai + i, kuai + i + sqn);
        ++num;
    }
    char p;
    int l, r, c;
    while (q--){
        cin >> p >> l >> r >> c;
        int numl = (l + sqn - 1) / sqn, numr = (r + sqn - 1) / sqn;
        if (p == 'M'){
            if (l > L[numl]){
                while (l < R[numl]) a[l++] += c;
                for (int i = L[numl]; i < R[numl]; ++i) kuai[i] = a[i];
                sort(kuai + L[numl], kuai + R[numl]);
                ++numl;
            }
            if (r < R[numr] - 1){
                while (r >= L[numr]) a[r--] += c;
                for (int i = L[numr]; i < R[numr]; ++i) kuai[i] = a[i];
                sort(kuai + L[numr], kuai + R[numr]);
                --numr;
            }
            while (numl <= numr){
                tag[numl++] += c;
            }
        }else{
            int ans = 0;
            if (l > L[numl]){
                while (l < R[numl]){
                    if (a[l++] + tag[numl] >= c) ++ans;
                }
                ++numl;
            }
            if (r < R[numr] - 1){
                while (r >= L[numr]){
                    if (a[r--] + tag[numr] >= c) ++ans;
                }
                --numr;
            }
            while (numl <= numr){
                ans += (R[numl] - L[numl]) - (lower_bound(kuai + L[numl], kuai + R[numl], c - tag[numl]) - (kuai + L[numl]));
                ++numl;
            }
            cout << ans << '\n';
        }
    }
    return 0;
}

等于(==、!=)的优先级比位运算(&、^、|)要高!
一起写的时候记得加括号!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值