題目
剛剛學了樹狀陣列的區間加法和區間求和操作,就用來水掉這題了
本篇適合學會樹狀陣列的人群
前置芝士:
普通樹狀陣列
差分樹狀陣列
學過樹狀陣列的人都知道,我們對於乙個陣列,進行處理後,就可以在 \(o(\log n)\) 的時間內進行單點修改和區間求和
假設對於陣列 \(a_n\) ,我們用樹狀陣列的方法處理後,就可以單點修改任意 \(a_i\) 的值,或者求 \(\displaystyle \sum_^r a_n\)
如果我們差分一下 \(a_n\) ,設 \(c_n=a_n-a_\) ,那就可以使得樹狀陣列區間修改和單點查詢 \(\displaystyle a_n=\sum_^n c_i\)
在差分的基礎下,我們如果需要求區間和,則先相同地:
\(\displaystyle \sum_^ra_i=\sum_^ra_i-\sum_^a_i\)
所以,在此基礎上,我們只需要求解 \(\displaystyle \sum_^k a_i\) 即可求解區間求和問題了
我們變型這個式子:
\(\displaystyle \sum_^k a_i=\sum_^k\sum_^ic_i=\sum_^k(k+1-i)c_i\)
這玩意兒沒辦法直接求,所以我們把它分開來:
\(\displaystyle \sum_^k a_i=(k+1)\sum_^k c_i-\sum_^k ic_i\)
這樣,就能分開來,用樹狀陣列實現求和了。
因此,我們只需要實現 \(c_n\) 和 \(nc_n\) 的樹狀陣列,即可以實現區間求和
即前者: \(c_n\) 差分樹狀陣列的區間和,乘上 \((k+1)\) ,減去後者: \(nc_n\) 差分樹狀陣列的區間和
當然,我們還應考慮修改對吧
假設修改區間 \([l,r]\) 都加上 \(a\)
首先, \(c_n\) 的修改肯定是沒問題的:\(c_l+=a,c_+=-a\)
分解為差分樹狀陣列單點修改 \(c_l\) 和 \(c_\)
而我們很清楚,假設 \(c_i\) 轉變為 \((c_i+a)\)
則有 \(ic_i\) 轉變為 \(i(c_i+a)=ic_i+ia\)
也就是說,\(ic_i+=ia\) ,而 \(ic_i\) 的增加對本身累加了 \(ic_i\) 的貢獻都是增加 \(ia\) 的
所以只要在修改 \(c_i+=a\) 的時候,順便修改 \(ic_i+=ia\) 即可
那本蒟蒻就放 我碼風極醜的 **了:
#includeusing namespace std;
#define f(a,b,c,d) for(register int a=b,c=d;a<=c;a++)
#define g(a,b,c,d) for(register int a=b,c=d;a>=c;a--)
#define local
typedef int i32;
typedef unsigned int u32;
typedef long long int i64;
typedef unsigned long long int u64;
const i32 maxn=1e5+10;
typedef i64 ar[maxn];
//一堆條件反射的定義
namespace habit
#else
inline char gc() ,*p1=s,*p2=s;
return (p1==p2)&&(p2=(p1=s)+fread(s,1,1<<20,stdin),p1==p2)?eof:*(p1++);
}#endif
inline i32 read()
char output_ans[1<<20|1],*output_cur=output_ans;
inline void output()
inline void print(char c)
inline void print(char *s)
inline void print(u64 x)
char buf[30]=,*p=buf+28;
while(x) *(p--)=x%10+48,x/=10;
print(p+1);
}inline void print(i64 x)
}using namespace habit;
//正文開始
i32 d_n,d_m;
ar ar_d_ic,ar_d_c;
inline void add(i32 pos,i64 a)
inline i64 sum(i32 pos)
inline void update(i32 h,i32 t,i64 a)
inline i64 query(i64 h,i64 t)
int main()
else
output();
return 0;
}
最後安利以下 本蒟蒻的部落格 題解 P3372 模板 線段樹1
看了一下題解裡的zkw線段樹,感覺講的不是很清楚啊 可能有清楚的但是我沒翻到,望大佬勿怪 決定自己寫一篇。希望大家能看明白。zkw線段樹是一種優秀的非遞迴線段樹,速度比普通線段樹快兩道三倍,同時 量不大。當然,存在很多線段樹可做zkw不可做的題 zkw線段樹的核心思路就是先修改葉子,然後從底向上沿著...
P3372 模板 線段樹 1
線段樹學習 這個題來看,線段樹分為建樹,更新,查詢。1.建樹 void build ll p,ll l,ll r ll mid l r 1 build lson p l,mid build rson p mid 1,r push up sum p void push up sum ll p 這段 的...
P3372 模板 線段樹 1
題 include includeusing namespace std typedef long long ll ll n,m,ans,x,y,op,val 因為下面有的函式需要用到x,y,val值,懶得傳參,故直接寫為全域性變數 const int n 100000 struct nodetre...