• 题解【loj6277】数列分块入门1


    题目描述

    给出一个长为(n)的数列,以及(n)个操作,操作涉及区间加法,单点查值。

    输入格式

    第一行输入一个数字(n)

    第二行输入(n)个数字,第(i)个数字为(a_{i}),以空格隔开。

    接下来输入(n)行询问,每行输入四个数字(opt)(l)(r)(c),以空格隔开。

    (opt = 0),表示将位于([l, r])的之间的数字都加(c)

    (opt = 1),表示询问(a_{r})的值((l)(c)忽略)。

    输出格式

    对于每次询问,输出一行一个数字表示答案。

    样例

    样例输入

    4

    1 2 2 3

    0 1 3 1

    1 0 1 0

    0 1 2 2

    1 0 2 0

    样例输出

    2

    5

    数据范围与提示

    对于所有的数据,(1 leq n le 50000)(-2^{31} leq others、ans le 2_{31} - 1)

    题解

    这是一道很好的分块入门题。

    所谓分块,就是一种通过将一个序列分成多块后,在每块上打标记以实现快速区间修改,区间查询的一种算法。其均摊时间复杂度为(Thetasqrt{n})

    在一般情况下,每个块的长度都为(sqrt{n})

    分块,被尊称为优雅的暴力,因此它的代码难度也不算高。总之,比线段树、树状数组等毒瘤数据结构的代码难度低。

    我们需要建立三个数组:

    • (a[]),为题目中输入的序列;
    • (b[]),记录每个序列中的每个数在那一块;
    • (add[]),为序列的标记数组。

    话不多说,上代码。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cctype>//头文件准备
    
    using namespace std;//使用标准名字空间
    
    inline int gi()//快速读入
    {
    	int f = 1, x = 0; char c = getchar();
    	while (c < '0' || c > '9') { if (c == '-')f = -1; c = getchar();}
    	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar();}
    	return f * x;
    }
    
    int a[50005], b[50005], add[50005], len, n, m;//a[],b[],add[]的意思如分析,len为每一块的长度,n为序列长度,m为询问个数,在本题中=n。
    
    inline void modify(int l, int r, int x)//区间修改的自定义函数
    {
    	for (int i = l; i <= min(r, b[l] * len); i++) a[i] = a[i] + x;//增加序列中的数
    	if (b[l] != b[r])//如果要修改的不在同一个块中
    	{
    		for (int i = (b[r] - 1) * len + 1; i <= r; i++) a[i] = a[i] + x;//继续增加序列中的数
    	}
    	for (int i = b[l] + 1; i <= b[r] - 1; i++) add[i] = add[i] + x;//给区间内的数增加标记
    }
    
    int main()//进入主函数
    {
    	n = gi();//输入元素个数
    	len = sqrt(n);//求出每个块的长度
    	for (int i = 1; i <= n; i++) a[i] = gi();//输入序列中的数
    	for (int i = 1; i <= n; i++) b[i] = (i - 1) / len + 1;//求出序列中的数分别属于哪一个块
        for (int p = 1; p <= n; p++)
    	{
    		int fl = gi(), l = gi(), r = gi(), w = gi();//输入操作的描述
    		if (!fl)//如果是修改
    		{
    			modify(l, r, w);//修改区间内的数
    		}
    		else//否则就是求出某个数
    		{
    			printf("%d
    ", a[r] + add[b[r]]);//输出这个位置的数的标记和它在序列中原本的数的和
    		}
    	}
    	return 0;//完美结束
    }
    
  • 相关阅读:
    Teleport垃圾代码tppabs的清理
    MVC Action 返回类型[转]
    Jquery 技巧收集..慢慢添加吧..
    下拉框根据输入文字自动选择和输入提示
    Repeater中,寻找TextBox,Lable.等的值
    纯CSS列自适应高
    一些基本的项目开发规范.慢慢总结中..
    MSSQL触发器
    IIS错误集,以及解决方法!
    C#创建Windows服务
  • 原文地址:https://www.cnblogs.com/xsl19/p/11104955.html
Copyright © 2020-2023  润新知