1. 程式人生 > >藍書(演算法競賽進階指南)刷題記錄——POJ3468 A Simple Problem with Intergers(樹狀陣列維護差分)

藍書(演算法競賽進階指南)刷題記錄——POJ3468 A Simple Problem with Intergers(樹狀陣列維護差分)

題目:poj3468.

題目大意:給定一個序列a,要求支援:

1.格式C a b c,表示將[a,b]的權值都加上c.

2.格式Q a b,表示查詢[a,b]的權值和.

線段樹裸題(我像個傻子一樣寫了個LCT做了一遍),可是我們這裡不用線段樹,我們討論樹狀陣列的解法.

我們已經知道樹狀陣列支援單點修改區間查詢區間修改單點查詢,那麼可不可以讓樹狀陣列支援區間修改區間查詢呢?

我們現在繼續將思路留在差分陣列上,我們設A是a的差分陣列,那麼A[1,n]的和就是\sum_{i=1}^{n}\sum_{j=1}^{i}A[i]=\sum_{i=1}^{n}A[i]*(n-i+1).

我們發現這個東西用一個樹狀陣列還是不好維護,我們可以在變式\sum_{i=1}^{n}A[i]*(n-i+1)=\sum_{i=1}^{n}A[i]*n-\sum_{i=1}^{n}A[i]*(i-1).

我們發現這個東西貌似就可以用兩個樹狀陣列維護,我們可以用一個樹狀陣列維護A[i],再用一個樹狀陣列維護A[i]*(i-1).

程式碼如下:

//#include<bits/stdc++.h>
#include<iostream>
  using namespace std;
#define Abigail inline void
typedef long long LL; 
const int N=100000;
LL c[N+9][2],a[N+9];
int n,q;
int lowbit(int x){return x&-x;}
void add(int x,LL num,int t){
  while (x<=n){
    c[x][t]+=num;
    x+=lowbit(x);
  }
}
LL query(int x,int t){
  LL sum=0;
  while (x){
    sum+=c[x][t];
    x-=lowbit(x);
  }
  return sum;
}
char rc(){
  char c=getchar();
  while (c<'A'||c>'Z') c=getchar();
  return c;
}
Abigail into(){
  scanf("%d%d",&n,&q);
  for (int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
}
Abigail work(){
  for (int i=n;i>=1;i--)
    a[i]-=a[i-1];
  for (int i=1;i<=n;i++)
    add(i,a[i],0),add(i,a[i]*(i-1),1);
}
Abigail getans(){
  char opt;
  int l,r;
  LL d;
  for (int i=1;i<=q;i++){
    opt=rc();
    if (opt=='C'){
      scanf("%d%d%lld",&l,&r,&d);
      add(l,d,0);add(r+1,-d,0);
      add(l,d*(l-1),1);add(r+1,-d*r,1);
    }else{
      scanf("%d%d",&l,&r);
      printf("%lld\n",query(r,0)*r-query(r,1)-query(l-1,0)*(l-1)+query(l-1,1));
    }
  }
}
int main(){
  into();
  work();
  getans();
  return 0;
}