首页 > 其他分享 >LOJ 数列分块入门2

LOJ 数列分块入门2

时间:2024-10-11 15:44:52浏览次数:7  
标签:零散 数列 分块 LOJ 整块 int MAXN

算法

考虑求小于给定值的数的个数,可以给每个块再维护一个已经排好序的数组,整块加法对于这个块排好序的数组没有影响,零散块加法直接在原序列上加,再将零散块所处的整块从新排序。查询时零散块暴力查找,整块二分查找

代码

#include <bits/stdc++.h>
#define int long long
const int MAXN = 1e6;

int n;
int Num[MAXN];

struct block
{
    int Left;
    int Right;
    int Size;
    int tmp[400];
    int cnt = 0;
    int add = 0;
} Blocks[400];
int Pos[MAXN];

bool cmp(int a, int b);

void Sort(int x)
{
    for (int i = Blocks[x].Left; i <= Blocks[x].Right; i++)
    {
        Blocks[x].tmp[++Blocks[x].cnt] = Num[i];
        // Pos[i] = x;
    }
    std::sort(Blocks[x].tmp + 1, Blocks[x].tmp + Blocks[x].Size + 1);
}

void Split()
{
    int Block_Size = sqrt(n);
    int Block_Num = n / Block_Size;
    if (n % Block_Size)
        Block_Num++;

    for (int i = 1; i < Block_Num; i++)
    {
        Blocks[i].Left = (i - 1) * Block_Size + 1;
        Blocks[i].Right = i * Block_Size;
        Blocks[i].Size = Block_Size;
        Sort(i);
    }
    Blocks[Block_Num].Left = Blocks[Block_Num - 1].Right + 1;
    Blocks[Block_Num].Right = n;
    Blocks[Block_Num].Size = Blocks[Block_Num].Right - Blocks[Block_Num].Left + 1;
    Sort(Block_Num);

    for (int i = 1; i <= n; i++)
    {
        Pos[i] = (i - 1) / Block_Size + 1;
    }
}

void Change(int Left, int Right, int Aim)
{
    int Left_Block = Pos[Left], Right_block = Pos[Right];

    if (Left_Block == Right_block)
    {
        for (int i = Left; i <= Right; i++)
        {
            Num[i] += Aim;
        }
        for (int i = Blocks[Left_Block].Left; i <= Blocks[Left_Block].Right; i++)
        {
            Blocks[Left_Block].tmp[i - Blocks[Left_Block].Left + 1] = Num[i];
        }
        std::sort(Blocks[Left_Block].tmp + 1, Blocks[Left_Block].tmp + Blocks[Left_Block].Size + 1);
    }
    else
    {
        for (int i = Left_Block + 1; i <= Right_block - 1; i++)
        {
            Blocks[i].add += Aim;
        }
        for (int i = Left; i <= Blocks[Left_Block].Right; i++)
        {
            Num[i] += Aim;
        }
        for (int i = Blocks[Left_Block].Left; i <= Blocks[Left_Block].Right; i++) //
        {
            Blocks[Left_Block].tmp[i - Blocks[Left_Block].Left + 1] = Num[i];
        }
        std::sort(Blocks[Left_Block].tmp + 1, Blocks[Left_Block].tmp + Blocks[Left_Block].Size + 1);

        for (int i = Blocks[Right_block].Left; i <= Right; i++)
        {
            Num[i] += Aim;
            Blocks[Right_block].tmp[i - Blocks[Right_block].Left + 1] = Num[i];
        }
        for (int i = Blocks[Right_block].Left; i <= Blocks[Right_block].Right; i++)
        {
            Blocks[Right_block].tmp[i - Blocks[Right_block].Left + 1] = Num[i];
        }
        std::sort(Blocks[Right_block].tmp + 1, Blocks[Right_block].tmp + Blocks[Right_block].Size + 1);
    }
}

int Find(int Left, int Right, int Aim)
{
    int Left_Block = Pos[Left], Right_block = Pos[Right];
    int Ans = 0;
    if (Left_Block == Right_block)
    {
        for (int i = Left; i <= Right; i++)
        {
            if (Num[i] + Blocks[Pos[i]].add < Aim)
                Ans++;
        }
    }

    else{
        for (int i = Left_Block + 1; i <= Right_block - 1; i++)
        {
            Ans += std::lower_bound(Blocks[i].tmp + 1, Blocks[i].tmp + Blocks[i].cnt + 1, Aim - Blocks[i].add) - (Blocks[i].tmp) - 1; //
        }
        for (int i = Left; i <= Blocks[Left_Block].Right; i++)
        {
            if (Num[i] + Blocks[Left_Block].add < Aim)
                Ans++;
        }

        for (int i = Blocks[Right_block].Left; i <= Right; i++)
        {
            if (Num[i] + Blocks[Right_block].add < Aim)
                Ans++;
        }
    }

    return Ans;
}

signed main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &Num[i]);
    }

    Split();

    for (int i = 1; i <= n; i++)
    {
        int op, l, r, c;
        scanf("%lld %lld %lld %lld", &op, &l, &r, &c);
        if (op == 0)
            Change(l, r, c);
        else
            printf("%lld\n", Find(l, r, c * c));
    }

    return 0;
}

bool cmp(int a, int b)
{
    return a < b;
}

/*
4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2

3
0
2
*/

总结

查找数列中 \(\geq\) 一个数, 可以用 std::lower_bound(a + 1, a + len + 1, Aim) - (a), 注意最后 (a) 不加 \(1\)

分块处理时注意零散块更改会影响随后整块的更改

标签:零散,数列,分块,LOJ,整块,int,MAXN
From: https://www.cnblogs.com/YzaCsp/p/18458537

相关文章

  • 洛谷P2513 逆序对数列
    Problem给定n,k,求得1~n中有多少种排列使得逆序对个数为k?(n,k<=1000)Solve考虑DP:设f[i][j]为i个数中逆序对数量为j的排列数量但因为我们并不知道我们这i个数到底是谁,难以通过以前的状态得到设f[i][j]为将i放入之前的排列后,逆序对数量为k的排列数此时我们发现可以确定前i-1......
  • 【JS】requestIdleCallback实现分块执行
    点击按钮后,执行一个耗时较长的dom操作,页面很长时间没有响应,给用户一种卡死的现象<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0">&......
  • 张量矩阵乘法分块乘法概述
    张量矩阵乘法分块乘法概述介绍一下矩阵计算相关的内容,从最基本的算法,到Cutlass这些线性代数模版库,特别是Layout代数相关的内容,再逐渐细化到一些硬件实现访存优化和一些算子融合。6.3.1GEMM概述1.GEMM定义对于一个矩阵乘法,定义如下: (6-1)一个矩阵乘法定义,如图6-26......
  • 矩阵分块乘法
    矩阵分块乘法通常可以把一个矩阵分成多个块,例如, (6-4)可以将其划分为4个块:   (6-5)   (6-6)分块后的矩阵记为:(6-7)分块矩阵乘法如下所示:(6-7)划分不一定需要完全等间隔,只需要满足子矩阵乘法规则即可,如图6-27所示。图6-27子矩阵划分不一定需要完全......
  • LOJ 6041 事情的相似度 题解
    Statement先把串reverse,多次给\(l,r\),求\[\max_{l\lei<j\ler}\{\text{LCP}(i,j)\}\]Solution\(\text{sqrtlog}\sim\text{sqrt}\):莫队+线段树/树状数组/set,用SA做\(nm/\omega\):bitset乱搞\(\log^2\):SAM+LCT+BIT在parent树上,LCP等于LCA的......
  • 数列 题解
    题意给出一张联通图,图上每个点有红蓝两色,给每一条边都赋一个权值,使得所有的红边构成一颗最小生成树,且权值是\(1\)到\(m\)的排列,求字典序最小的情况。题解对于一条蓝边,其权值一定小于除它以外全是红边的环上的所有红边的权值(有点绕),否则就构不成一颗生成树。所以只需要按顺......
  • LOJ6077 逆序对
    lojcwoi题意求逆序对数恰为\(m\)的长度为\(n\)的排列数。\(n,m\le10^5\)。solution\(n,m\le5000\)首先对于更小的数据可以直接状压。进一步观察,发现我们并不需要知道值之间的具体大小,只用相对大小就能计算贡献了。于是设\(f_{i,j}\)表示长为\(i\),逆序对数为......
  • 信息学奥赛复赛复习11-CSP-J2020-04方格取数-动态规划、斐波那契数列、最优子结构、重
    PDF文档公众号回复关键字:202410041P7074[CSP-J2020]方格取数[题目描述]设有n×m的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中......
  • 【递归】小q的数列
    https://ac.nowcoder.com/acm/contest/21763/1002pow(2,ans)计算的是2的ans次幂,但是pow()函数返回的是double类型的结果。由于pow()函数主要用于浮点数计算,它返回浮点数结果,而后你可能需要对该结果进行整数操作。如果不进行显式类型转换,这个浮点数结果会丢失精度,特别是在......
  • [Violet] 蒲公英(分块)
    区间众数要求即有次数又要数字最小#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglongull;typedefunsignedintuint;typedefvector<string>VS;typedef......