#6277. 数列分块入门 1

题目链接:https://loj.ac/problem/6277

学习博客:http://hzwer.com/8053.html

#6277. 数列分块入门 1

内存限制:256 MiB时间限制:100 ms标准输入输出
题目类型:传统评测方式:文本比较
上传者: hzwer

题目描述

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

输入格式

第一行输入一个数字 nn。

第二行输入 nn 个数字,第 ii 个数字为 a_iai,以空格隔开。

接下来输入 nn 行询问,每行输入四个数字 \mathrm{opt}opt、ll、rr、cc,以空格隔开。

若 \mathrm{opt} = 0opt=0,表示将位于 [l, r][l,r] 的之间的数字都加 cc。

若 \mathrm{opt} = 1opt=1,表示询问 a_rar 的值(ll 和 cc 忽略)。

输出格式

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

样例

样例输入

4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0

样例输出

2
5

数据范围与提示

对于 100\%100% 的数据,1 \leq n \leq 50000, -2^{31} \leq \mathrm{others}1n50000,231others、\mathrm{ans} \leq 2^{31}-1ans2311。

思路:这题可以用很多种数据结构来写,这里就只用分块

看代码:

#include<iostream>
#include<math.h>
#include<stdlib.h>
#include<stdio.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=50000+5;
int a[maxn];
int bl[maxn];//bl[i]代表第i个数位于哪个块
int atag[maxn];//存储一个一块全部加的值
int block;//块的大小
void add(int l,int r,int c)
{
    for(int i=l;i<=min(bl[l]*block,r);i++) a[i]+=c;//最左边的一个整块
    if(bl[l]!=bl[r])//不在一个块时 
    {
        for(int i=(bl[r]-1)*block+1;i<=r;i++) a[i]+=c;//最右边的一个整块
    }
    for(int i=bl[l]+1;i<=bl[r]-1;i++) atag[i]+=c;//中间的整块
}
int main()
{
    int n;
    int opt,l,r,c;
    scanf("%d",&n);
    block=sqrt(n);//每个块的大小
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);//输入区间
    for(int i=1;i<=n;i++) bl[i]=(i-1)/block+1;//分块  
    //这里为什么是(i-1)/block+1呢 比如block=2  那么1 2 是属于第一个块的 3 4属于第二个块 这样处理刚好能满足需求
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&opt,&l,&r,&c);
        if(opt==0) add(l,r,c);
        else printf("%d\n",a[r]+atag[bl[r]]);
    }
    return 0;
}

 

posted @ 2019-01-22 15:52  执||念  阅读(364)  评论(2编辑  收藏  举报