题意
维护一个数据结构,使得能进行两种操作
1.查询[l,r]内a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r]之和,L是区间长度。
2.单点更新一个值
思路
线段树和树状数组只能维护区间和,但此题每项有与区间长度相关的权值。
聪明的鸡神想到了三角形法,分别维护(n-i)*a[i]和a[i],在查询时我们算第一个区间和减去第二个区间和乘以(n-r)的差就行了,然后我们神奇的得到了目标和。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+7; 4 long long tree[2][N]; 5 void add(int x,long long val,int num) 6 { 7 while(x<N) 8 { 9 tree[num][x]+=val; 10 x+=x&-x; 11 } 12 } 13 long long sum(int x,int num) 14 { 15 long long ret=0; 16 while(x>0) 17 { 18 ret+=tree[num][x]; 19 x-=x&-x; 20 } 21 return ret; 22 } 23 int main() 24 { 25 int n,q; 26 while(scanf("%d%d",&n,&q)==2) 27 { 28 memset(tree,0,sizeof(tree)); 29 for(int i=1;i<=n;i++) 30 { 31 long long temp; 32 scanf("%lld",&temp); 33 add(i,1LL * temp*(n-i+1),0); 34 add(i,temp,1); 35 } 36 while(q--) 37 { 38 int op; 39 long long a,b; 40 scanf("%d%lld%lld",&op,&a,&b); 41 if(op==1) 42 { 43 long long ans=0; 44 ans=sum(b,0)-sum(a-1,0)-(n-b)*(sum(b,1)-sum(a-1,1)); 45 printf("%lld ",ans); 46 } 47 else{ 48 long long temp; 49 temp=sum(a,1)-sum(a-1,1); 50 add(a,-temp+b,1); 51 add(a,-temp*(n-a+1)+b*(n-a+1),0); 52 } 53 } 54 } 55 return 0; 56 }
后记
鸡神太聪明了!