• 洛谷P3870 [TJOI2009] 开关 题解 数列分块


    题目链接:https://www.luogu.com.cn/problem/P3870

    涉及操作:

    1. 区间取反;
    2. 区间和。

    其中, \(sum[i]\) 表示第 \(i\) 个分块的元素和,\(tag[i]\) 表示整体是否需要取反。

    示例程序:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 100010;
    int n, m, blo, a[maxn], bl[maxn], sum[505], tag[505];
    // 将区间[l,r]取反
    void update(int l, int r) {
        for (int i = l; i <= min(r, bl[l]*blo); i ++) {
            sum[bl[i]] -= a[i] ^ tag[bl[i]];
            a[i] ^= 1;
            sum[bl[i]] += a[i] ^ tag[bl[i]];
        }
        if (bl[l] != bl[r]) {
            for (int i = (bl[r]-1)*blo+1; i <= r; i ++) {
                sum[bl[i]] -= a[i] ^ tag[bl[i]];
                a[i] ^= 1;
                sum[bl[i]] += a[i] ^ tag[bl[i]];
            }
        }
        for (int i = bl[l]+1; i < bl[r]; i ++)
            tag[i] ^= 1, sum[i] = blo - sum[i];
    }
    // 区间[l,r]求和
    int query(int l, int r) {
        int res = 0;
        for (int i = l; i <= min(r, bl[l]*blo); i ++)
            res += a[i] ^ tag[bl[i]];
        if (bl[l] != bl[r]) {
            for (int i = (bl[r]-1)*blo+1; i <= r; i ++)
                res += a[i] ^ tag[bl[i]];
        }
        for (int i = bl[l]+1; i < bl[r]; i ++) {
            res += sum[i];
        }
        return res;
    }
    int main() {
        cin >> n >> m;
        blo = sqrt(n);
        for (int i = 1; i <= n; i ++)
            bl[i] = (i - 1) / blo + 1;
        while (m --) {
            int op, x, y;
            cin >> op >> x >> y;
            assert(1 <= x && x <= y && y <= n);
            if (op == 0) update(x, y);
            else cout << query(x, y) << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    Java基础知识_毕向东_Java基础视频教程笔记(5-10 面向对象)
    Java 运算符-=,+=混合计算详解
    VS Code 基本介绍 和 快捷键
    Access-Control-Allow-Origin 跨域问题
    Linux常用命令收藏
    常用正则表达式
    IntelliJ IDEA 快捷键列表
    PAT A除以B
    PAT 部分A+B
    PAT 德才论
  • 原文地址:https://www.cnblogs.com/quanjun/p/15578023.html
Copyright © 2020-2023  润新知