#include<stdio.h> struct CNode { int L,R; long long nSum; long long Inc; CNode *pLeft,*pRight; }; CNode Tree[1000000]; int nCount; int Mid(CNode *pRoot) { return (pRoot->L+pRoot->R)/2; } void BuildTree(CNode *pRoot,int L,int R) { pRoot->L=L; pRoot->R=R; pRoot->nSum=0; pRoot->Inc=0; if(L==R) return ; nCount++; pRoot->pLeft=Tree+nCount; nCount++; pRoot->pRight=Tree+nCount; BuildTree(pRoot->pLeft,L,(L+R)/2); BuildTree(pRoot->pRight,(L+R)/2+1,R); } void Insert(CNode *pRoot,int i,int v) { if(pRoot->L==i&&pRoot->R==i) { pRoot->nSum=v; return ; } pRoot->nSum+=v; if(i<=Mid(pRoot)) Insert(pRoot->pLeft,i,v); else Insert(pRoot->pRight,i,v); } void Add(CNode *pRoot,int a,int b,long long c) { if(pRoot->L==a&&pRoot->R==b) { pRoot->Inc+=c; return ; } pRoot->nSum+=c*(b-a+1); if(b<=Mid(pRoot)) Add(pRoot->pLeft,a,b,c); else if(a>Mid(pRoot)) Add(pRoot->pRight,a,b,c); else { Add(pRoot->pLeft,a,Mid(pRoot),c); Add(pRoot->pRight,Mid(pRoot)+1,b,c); } } long long QuerySum(CNode *pRoot,int a,int b) { if(pRoot->L==a&&pRoot->R==b) { return pRoot->nSum+(pRoot->R-pRoot->L+1)*pRoot->Inc; } pRoot->nSum+=(pRoot->R-pRoot->L+1)*pRoot->Inc; Add(pRoot->pLeft,pRoot->L,Mid(pRoot),pRoot->Inc); Add(pRoot->pRight,Mid(pRoot)+1,pRoot->R,pRoot->Inc); pRoot->Inc=0; if(b<=Mid(pRoot)) return QuerySum(pRoot->pLeft,a,b); else if(a>Mid(pRoot)) return QuerySum(pRoot->pRight,a,b); else { return QuerySum(pRoot->pLeft,a,Mid(pRoot))+ QuerySum(pRoot->pRight,Mid(pRoot)+1,b); } } int main() { int n,q,a,b,c; int i,j,k; char cmd[10]; scanf("%d%d",&n,&q); nCount=0; BuildTree(Tree,1,n); for(i=1;i<=n;i++) { scanf("%d",&a); Insert(Tree,i,a); } for(i=0;i<q;i++) { scanf("%s",cmd); if(cmd[0]=='C') { scanf("%d%d%d",&a,&b,&c); Add(Tree,a,b,c); } else { scanf("%d%d",&a,&b); printf("%d ",QuerySum(Tree,a,b)); } } return 0; }
在增加时,如果要加的区间正好覆盖一个
节点,则增加其节点的Inc值,不再往下走
,否则要更新nSum,再将增量往下传
这样更新的复杂度就是O(log(n))
在查询时,如果待查区间不是正好覆盖一
个节点,就将节点的Inc往下带,然后将Inc
代表的所有增量累加到nSum上后将Inc清0
,接下来再往下查询。 Inc往下带的过程也是
区间分解的过程,复杂度也是O(log(n))