【题目大意】
有n个数,a1,a2,a3,…,an,有Q个操作。(1 ≤ N,Q ≤ 100000)
操作分两种
C a b c 表示将区间[a,b]上的每个数都加上c (-10000 ≤ c ≤ 10000)。
Q a b 表示输出区间[a,b]的和。
【解题思路】
可以用线段树解决。
也可以用树状数组解决这种改一段查一段的区间和问题。
原数组为a[i]
令d[i]=a[i]-a[i-1]
sum(1,k)=a[1]+a[2]+a[3]+…+a[k-1]+a[k]
=(d[1])+(d[1]+d[2])+(d[1]+d[2]+d[3])+…+(d[1]+d[2]+d[3]+…+d[k])
=k*(d[1]+d[2]+d[3]+…+d[k-1]+d[k])-(0d[1]+1d[2]+2d[3]+…+(k-1)d[k])
用树状数组c1 维护d[1]+d[2]+d[3]+…+d[i]的和
用树状数组c2 维护0d[1]+1d[2]+2*d[3]+…+(k-1)*d[k]的和
【代码】
/*LG3368
树状数组区间修改,区间查询
原数组为a[i]
令d[i]=a[i]-a[i-1]
sum(1,k)=a[1]+a[2]+a[3]+...+a[k-1]+a[k]
=(d[1])+(d[1]+d[2])+(d[1]+d[2]+d[3])+...+(d[1]+d[2]+d[3]+...+d[k])
=k*(d[1]+d[2]+d[3]+...+d[k-1]+d[k])-(0*d[1]+1*d[2]+2*d[3]+...+(k-1)*d[k])
用树状数组c1[] 求d[1]+d[2]+d[3]+...+d[i]的和
用树状数组c2[] 求0*d[1]+1*d[2]+2*d[3]+...+(k-1)*d[k]的和
*/
#include <cstdio>
using namespace std;
int a[505050],c1[505050],c2[505050];
int n,m;
int lowbit(int x)
{
return (x&(-x));
}
void updata(int x,int k)
{
int t=x;
while (x<=n)
{
c1[x]+=k;
c2[x]+=(t-1)*k;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans1=0;
int ans2=0;
int t=x;
while (x>0)
{
ans1+=c1[x];
ans2+=c2[x];
x-=lowbit(x);
}
return (t*ans1-ans2);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
updata(i,a[i]-a[i-1]);
}
for (int i=1;i<=m;i++)
{
int sym;
scanf("%d",&sym);
if (sym==1)
{
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
updata(x,k);
updata(y+1,-k);
}else
{
int k;
scanf("%d",&k);
int ans=sum(k)-sum(k-1);
printf("%d\n",ans);
}
}
}