数列分块入门 1
题目描述
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。
输入格式
第一行输入一个数字 n。
第二行输入n 个数字,第 i 个数字为 ai,以空格隔开。
接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。
若 opt==0,表示将位于[l,r] 的之间的数字都加 c 。
若 opt==1,表示询问 ar 的值(l 和 c忽略)。
输出格式
对于每次询问,输出一行一个数字表示答案。
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstring> #include<stdio.h> #include<algorithm> #include<map> #include<queue> #include<set> #include <sstream> #include<vector> #include<cmath> #include<stack> #include<random> using namespace std; #define io ios::sync_with_stdio(0),cin.tie(0) #define ms(arr) memset(arr,0,sizeof(arr)) #define LD long double #define LL long long #define PI acos(-1.0) #define INF 0x3f3f3f3f #define inf 1<<30 #define ull unsigned long long const int Mod = 998244353; const int maxn = 1e6 + 5; int read() { int x = 0, f = 1; char ch = getchar(); while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int n,opt,l,r,c,block,num; LL L[maxn],R[maxn],belong[maxn],change[maxn]; LL a[maxn]; void build() { block=sqrt(n);//分块操作,每一个块的大小为sqrt(n) num=n/block;//一共分成num个块 if(n%block)num++;//如果有剩,num+1 for(int i=1;i<=num;i++){ L[i]=(i-1)*block+1; //第i个块的左边界 R[i]=i*block; //第i个块的右边界 } R[num]=n; //第num个块的右边界为n for(int i=1;i<=n;i++){ //遍历n个数 belong[i]=(i-1)/block+1;//确定第i个数属于第几个块 } } void add(int x,int y,int val) { if(belong[x]==belong[y]){//如果x和y属于同一个块 for(int i=x;i<=y;i++){//直接遍历就好,因为一个块的大小最多为sqrt(n) a[i]+=val; } } else{ for(int i=x;i<=R[belong[x]];i++){//遍历这个块的[x ,块的右边界] a[i]+=val; } for(int i=belong[x]+1;i<belong[y];i++){//遍历[x+1,y-1]的块,直接改变块的整体 change[i]+=val; } for(int i=L[belong[y]];i<=y;i++){//遍历这个块的[块的左边界,y] a[i]+=val; } } } int main(){ io; n=read(); for(int i=1;i<=n;i++){ a[i]=read(); } build();//分块 for(int i=1;i<=n;i++){ opt=read();l=read();r=read();c=read(); if(opt==0){ add(l,r,c); } else{ printf("%lld\n",a[r]+change[belong[r]]); } } return 0; }