#6277. 数列分块入门 1
题目链接:https://loj.ac/problem/6277
学习博客:http://hzwer.com/8053.html
题目描述
给出一个长为 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}1≤n≤50000,−231≤others、\mathrm{ans} \leq 2^{31}-1ans≤231−1。
思路:这题可以用很多种数据结构来写,这里就只用分块
看代码:
#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; }
当初的梦想实现了吗,事到如今只好放弃吗~