POJ 3468 線段樹區間更新
阿新 • • 發佈:2018-12-13
題意: 輸入 n, m表初始有 n 個數, 接下來 m 行輸入, Q x y 表示詢問區間 [x, y]的和;
C x y z 表示區間 [x, y] 內所有數加上 z ;
AC_code:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<map> #include<cstdlib> #define ll long long #define inf 0x3f3f3f3f//1e9+6e7 #define N 100010 #define debug(x) cout<<"X: "<<(x)<<endl #define de cout<<"**"<<endl #define lson rt<<1 #define rson rt<<1|1 const double pi=acos(-1.0); using namespace std; ll sum[N<<2],add[N<<2]; int a[N]; int n; void push_up(int rt) //向上更新 { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void push_down(int rt,int m) { if(add[rt]) //若有標記,則將標記向下移動一層 { add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; sum[rt<<1]+=(m-(m>>1))*add[rt]; sum[rt<<1|1]+=(m>>1)*add[rt]; add[rt]=0; //取消本層標記 } } void build(int l,int r,int rt) //建樹 { add[rt]=0; if(l==r) { sum[rt]=a[l]; return ; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); push_up(rt); //向上更新 } void update(int i,int j,ll v,int l,int r,int rt) { if(i <= l && j >= r) { sum[rt] += (r - l + 1) * v; add[rt] += v; return; } push_down(rt, r - l + 1);//向下更新 int mid = (l + r) >> 1; if(i <= mid) update(i, j, v, l,mid,rt<<1); if(j > mid) update(i, j, v, mid+1,r,rt<<1|1); push_up(rt);//向上更新 } ll query(int L,int R,int l,int r,int rt) //區間求和 { if(L<=l&&r<=R) return sum[rt]; push_down(rt, r - l + 1); //向下更新 int m=(l+r)>>1; ll ans=0; if(L<=m) ans+=query(L,R,l,m,rt<<1); if(R>m) ans+=query(L,R,m+1,r,rt<<1|1); return ans; } int main() { int q; cin>>n>>q; for(int i=1; i<=n; i++) scanf("%d",&a[i]); memset(add,0,sizeof add); char s; build(1,n,1); int i,j; ll v; ll ans; while(q--) { cin>>s; if(s=='C') { scanf("%d%d%lld",&i,&j,&v); update(i,j,v,1,n,1); } if(s=='Q') { scanf("%d%d",&i,&j); ans=query(i,j,1,n,1); printf("%lld\n",ans); } } return 0; }