#include <iostream>#include <cmath>#include <cstring>#include <algorithm>using namespace std;int n,m;int a[100001]; // 葉子結點數N__int64 ans;struct{ int l,r; __int64 sum,add; //__int64 }tree[400000]; //數中所有結點數量大概為 2^2*N 層數logN h=logN+1 或+2 每次插入更新不超過 O(logN)void build(int l,int r,int i){ tree[i].l = l; tree[i].r = r; tree[i].add = 0; if(l == r) { tree[i].sum = a[l]; //葉子結點的值=輸入數組的值 return ; } int mid = (l+r)/2; build(l,mid,2*i); build(mid+1,r,2*i+1); tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;}void updata(int l,int r,int add,int i){ if(tree[i].l > r || tree[i].r < l) return ; if(tree[i].l >= l && tree[i].r <= r) { tree[i].sum += (tree[i].r-tree[i].l+1)*add; tree[i].add += add; return ; //lazy 只加到分解唯一的子區間 } if(tree[i].add) //lazy 邊更新邊維護 為了確保 孩子的 add和 sum正確 必須更新 且更新完後 當前add=0 (更新到最底)的意思 { tree[2*i].sum += (tree[2*i].r-tree[2*i].l+1)*tree[i].add; tree[2*i].add += tree[i].add; tree[2*i+1].sum += (tree[2*i+1].r-tree[2*i+1].l+1)*tree[i].add; tree[2*i+1].add += tree[i].add; tree[i].add = 0; } updata(l,r,add,2*i); updata(l,r,add,2*i+1); tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;}void query(int l,int r,int i){ if(tree[i].l > r || tree[i].r < l) return ; if(tree[i].l >= l && tree[i].r <= r) { ans += tree[i].sum; return ; } if(tree[i].add) //lazy 邊查詢邊維護 { tree[2*i].sum += (tree[2*i].r-tree[2*i].l+1)*tree[i].add; tree[2*i].add += tree[i].add; tree[2*i+1].sum += (tree[2*i+1].r-tree[2*i+1].l+1)*tree[i].add; tree[2*i+1].add += tree[i].add; tree[i].add = 0; } query(l,r,2*i); query(l,r,2*i+1); tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;}int main(){ //freopen("in.txt","r",stdin); int i,x,y,z; char c; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); scanf("%*c"); for(i=1;i<=m;i++) { scanf("%c",&c); if(c == 'Q') { scanf("%d%d%*c",&x,&y); ans = 0; query(x,y,1); printf("%I64d\n",ans); } else { scanf("%d%d%d%*c",&x,&y,&z); updata(x,y,z,1); } } } return 0;}
扒了一線段樹代碼 注釋作分析