首页 > 其他分享 >洛谷P7492 [传智杯 #3 决赛] 序列 题解 数列分块

洛谷P7492 [传智杯 #3 决赛] 序列 题解 数列分块

时间:2023-04-17 12:33:50浏览次数:57  
标签:tmp 传智杯 洛谷 分块 int 题解 long blo 400

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

解题思路:

分块。解题思路全部来自 yzy1大佬的博客

额外掌握技能:

编译时加入 -Wall 参数。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, blo,             // n表示数列长度,m表示操作次数,blo表示分块大小
        a[maxn],        // a[i]表示序列中第i个元素的数字
        v[400],         // v[i]表示第i个分块的所有元素的按位与
        bl[maxn];       // bl[i]表示序列中第i个元素所属的分块的编号
long long lsum[400],    // lsum[i]表示第i个分块的所有前缀对应的最大子段和
        rsum[400],      // rsum[i]表示第i个分块的所有后缀对应的最大子段和
        msum[400],      // msum[i]表示第i个分块(单独算)对应的最大子段和
        sum[400];       // sum[i]表示第i个分块中所有元素之和

// 更新第p个分块的信息
void upd(int p) {
    int l = (p - 1) * blo + 1, r = min(n, p * blo);
    lsum[p] = rsum[p] = msum[p] = sum[p] = 0;
    // 更新 msum[p] 和 sum[p]
    long long tmp = 0;
    for (int i = l; i <= r; i++) {
        tmp = max(tmp, 0ll) + a[i];
        msum[p] = max(msum[p], tmp);
        sum[p] += a[i];
    }
    // 更新 lsum[p]
    tmp = 0;
    for (int i = l; i <= r; i++) {
        tmp += a[i];
        lsum[p] = max(lsum[p], tmp);
    }
    // 更新 rsum[p]
    tmp = 0;
    for (int i = r; i >= l; i--) {
        tmp += a[i];
        rsum[p] = max(rsum[p], tmp);
    }
}

// 将第 p 个分块的所有元素整体按位或上k
void func_or(int p, int k) {
    if ((v[p] & k) == k)  // 如果第p个分块的所有元素在k为1的那些位也都为1了
        return;             // 则不用再进行按位或操作了
    v[p] |= k;
    for (int i = (p - 1) * blo + 1; i <= min(n, p * blo); i++)
        a[i] |= k;
    upd(p);
}

// 操作2:将 a[l..r] 都按位或上 k
void update(int l, int r, int k) {
    if (bl[l] == bl[r]) {
        for (int i = l; i <= r; i++)
            a[i] |= k;
        upd(bl[l]);
        return;
    }
    for (int i = l; i <= bl[l] * blo; i++)
        a[i] |= k;
    upd(bl[l]);
    for (int i = (bl[r] - 1) * blo + 1; i <= r; i++)
        a[i] |= k;
    upd(bl[r]);
    for (int i = bl[l]+1; i < bl[r]; i++)
        func_or(i, k);
}

// 操作1:查询 a[l..r] 的最大子段和
long long query(int l, int r) {
    long long res = 0, tmp = 0;
    if (bl[l] == bl[r]) {
        for (int i = l; i <= r; i++) {
            tmp = max(tmp, 0ll) + a[i];
            res = max(res, tmp);
        }
    }
    else {
        // 最左边的分块的最大子段和
        for (int i = bl[l] * blo; i >= l; i--) {
            tmp = max(tmp, 0ll) + a[i];
            res = max(res, tmp);
        }
        // 最左边的分块的最大后缀和
        long long sum1 = 0;
        tmp = 0;
        for (int i = bl[l] * blo; i >= l; i--) {
            tmp += a[i];
            sum1 = max(sum1, tmp);
        }
        for (int i = bl[l]+1; i <= bl[r]; i++) {
            if (i < bl[r]) {
                res = max(res, msum[i]);
                res = max(res, sum1 + lsum[i]);
                sum1 = max(sum1 + sum[i], rsum[i]);
            }
            else {  // i == bl[r]
                // 最右边的分块的最大子段和
                tmp = 0;
                for (int j = (bl[r]-1)*blo+1; j <= r; j++) {
                    tmp = max(tmp, 0ll) + a[j];
                    res = max(res, tmp);
                }
                // 最右边的分块的最大前缀和
                long long sum2 = 0;
                tmp = 0;
                for (int j = (bl[r]-1)*blo+1; j <= r; j++) {
                    tmp += a[j];
                    sum2 = max(sum2, tmp);
                }
                res = max(res, sum1 + sum2);
            }
        }
    }
    return res;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", a+i);
    blo = sqrt(n);
    for (int i = 1; i <= n; i++) bl[i] = (i - 1) / blo + 1;
    for (int i = 1; i <= bl[n]; i++) upd(i);
    while (m--) {
        int op, l, r, k;
        scanf("%d%d%d", &op, &l, &r);
        if (op == 1) {
            printf("%lld\n", query(l, r));
        }
        else {
            scanf("%d", &k);
            update(l, r, k);
        }
    }
    return 0;
}

标签:tmp,传智杯,洛谷,分块,int,题解,long,blo,400
From: https://www.cnblogs.com/quanjun/p/17325476.html

相关文章

  • abc250_d 250-like Number 题解
    250-likeNumber题意给定一个整数\(n\),求有多少小于等于\(n\)的满足以下条件的整数\(k\):\(k\)可以被表示为\(k=p\timesq^3\),其中\(p\ltq\),并且\(p,q\)均为质数。数据范围\(1\leqslantn\leqslant10^{18}\),\(n\)是整数。思路首先,我们发现这个式子中......
  • 洛谷T226686 长度为2的子串
    题目描述给你一个长度为n 的由大写的英文字母组成的字符串,请你找出出现频率最高的长度为2的子串。输入格式包括两行。第一行是一个正整数n,表示字符串长度。第二行是长度为n的大写英文字母组成的字符串。(2<=n<=100)输出格式包括一行。一个长度为2的字符串,该字符串为输入......
  • AT_agc003_e 题解
    题目链接神仙题,我会把我自己思考的过程一步步写出来。初看这题时感觉没什么思路,所以随便算了点东西。很容易发现如果对于一个$i$,$q_i\geqq_{i+1}$,那么$q_i$就没有意义,每次把元素放进来时先把头部比它大的都弹走,再把它放进去,设处理完的size为cnt。然后就是这道题的精髓所......
  • Atcoder题解:Agc002_f
    我们可以把这个理解成一种类似卡塔兰数的形式,我们发现,被安排的\(0\)球总数\(i\)和已经出现的颜色种数\(j\)在任意时刻都必须满足\(i\gej\)。然后就可以\(dp\)了,我们每次钦定下一个转移的球是某种颜色。如果下一个转移的球不是\(0\),那么我们就一次性把后面所有这种颜色......
  • Atcoder题解:Agc004_e
    \[吓死我了,还以为写了半天的被自己删掉了\]\[但是\text{Ctrl+S}会保存草稿啊\]\[以后一定要保留这个好习惯\]第一步转化题意,我们把“所有机器人移动”转化成“出口带着边框移动”,而在出口运动过程中超出边框的机器人,就“死”了。然后我们发现,出口运动过程中,假设出口目前走到......
  • js 传递汉字 乱码_JavaScript 字符串反转乱码问题解决
    https://blog.csdn.net/weixin_36483301/article/details/113451892emoji表情和非常用字实际解决中文编码问题,可以通过解码解决js中使用decodeURL即可解决......
  • Atcoder题解:Agc013_e
    我们考虑转化题意,一个合法的将\(1\simN\)划分成长度依次为\(a_1,a_2,\cdotsa_k\)的小区间,对答案的贡献为\(a_1^2a_2^2\cdotsa_k^2\)。化贡献为方案数,我们在每个长度为\(a_i\)的小区间内放置两个独立的标记,每个合法的划分方案对放置标记方案种数的贡献恰好是其对最终答......
  • CF题解
    D.ABGraph2000构造https://codeforces.com/problemset/problem/1481/D题解:由于只有两种边,我们可以枚举较小结构的特性并循环来构造整体解。对于任意两个点,[u->v,v->u]只有4种情况,对于[1,1],[0,0]直接得解,可以循环这个环来构造回文,否则[1,0],[0,1],注意到当所需回文为odd长时,......
  • abc249_f Ignore Operations 题解
    IgnoreOperations题意Takahashi有一个整数\(x\),初始\(x=0\)。有\(n\)次操作。第\(i\)次操作用两个整数\(t_i,y_i\)描述:如果\(t_i=1\),将整数\(x\)替换为\(y_i\)。如果\(t_i=2\),将整数\(x\)替换为\(x+y_i\)。Takahashi可以跳过其中至多\(K\)......
  • TJOI 2015 概率论 题解
    TJOI2015概率论题解题意求\(n\)个点随机生成的有根二叉树(所有互不同构的二叉树出现情况等概率)的叶子节点数的期望值。题解70答案显然是\(\dfrac{g(n)}{f(n)}\),\(g(n)\)是\(n\)个点为所有二叉树的叶子总数,\(f(n)\)是\(n\)个点能生成的二叉树数。一棵树可以用左......