给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。
Input
第一行输入一个数字 n。
第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。
接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。
若 opt=0,表示将位于 [l,r] 的之间的数字都加 c。
若 opt=1,表示询问 ar 的值(l 和 c 忽略)。
Output
对于每次询问,输出一行一个数字表示答案。
Example
样例输入
4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0
样例输出
2
5
Hint
对于 100% 的数据,1≤n≤50000,−231≤others、ans≤231−1。
解析:
分块入门 区间更新+单点查询
对于区间的更新:
1.如果更新的区间在同一块中,我们暴力更新即可
2.如果更新的区间在不在同一块中,我们就要暴力修改左侧和右侧不完整的块
对于中间完整的块用懒惰标记记录该块需要+v
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1000;
typedef long long ll;
ll a[N];
int l[N];//第i块的左端点
int r[N];//第i块的右端点
ll lazy[N];//对于完整的块 打上lazy
int pos[N]; //第i个点属于第几块
int op,u,v,x,n;
void add(int ql,int qr,ll x)
{
int pl=pos[ql];//要修改的区间左端点属于第几个块
int pr=pos[qr];//要修改的区间右端点属于第几个块
if(pl==pr)//属于同一块暴力修改
{
for(int i=ql;i<=qr;i++) a[i]+=x;
}
else //不同块中
{
for(int i=ql;i<=r[pl];i++) a[i]+=x; //暴力修改左侧不完整的块
for(int i=pos[ql]+1;i<=pos[qr]-1;i++) lazy[i]+=x; //计算中间完整的块
for(int i=l[pr];i<=qr;i++) a[i]+=x;//暴力修改右侧不完整的块
}
}
ll query(int i)
{
int x=pos[i];//看i是第几块的
if(lazy[x]) return a[i]+lazy[x];
else return a[i];
}
int main()
{
scanf("%d",&n);
int dis=sqrt(n);//块的大小
int num=ceil(1.0*n/dis);//分块的数量
for(int i=1;i<=n;i++) l[i]=(i-1)*dis+1,r[i]=i*dis;
r[num]=n;//最后一个块的右端点最大等于n
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pos[i]=(i-1)/dis+1;
for(int i=1;i<=n;i++)
{
cin>>op>>u>>v>>x;
if(op==0)
{
add(u,v,x);
}
else cout<<query(v)<<endl;
}
}