树状数组
关于树状数组
以 O(logn) 的时间复杂度查找、改变前缀和数组
要注意:
树状数组 c 里面存的不是对应点的值、也不是前缀和的值,是树状数组的值
但是可以利用树状数组对一个区间进行 log n 的时间复杂度的改变或求某点前缀和
//O(nlogn) 初始化
for(int i = 1;i <= n;i ++) add(i,a[i]);
楼兰图腾
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 200010;
int a[N],tr[N];
int n;
int g[N],l[N];
ll res1 = 0,res2 = 0;
int lowb(int x){
return x & -x;
}
// pos 位置加x
void add(int pos,int x){
for(int i = pos;i <= n;i += lowb(i)) tr[i] += x;
}
//求 1~pos
int sum(int pos){
int res = 0;
for(int i = pos;i;i -= lowb(i)) res += tr[i];
return res;
}
int main(){
cin >> n;
for(int i = 1;i <= n;i ++) cin >> a[i];
for(int i = 1;i <= n;i ++){
int temp = a[i];
g[i] = (sum(n) - sum(temp));
l[i] = sum(temp - 1);
add(temp,1);
}
memset(tr,0,sizeof tr);
for(int i = n;i;i --){
int temp = a[i];
res1 += (ll)g[i] * (sum(n) - sum(temp));
res2 += (ll)l[i] * sum(temp - 1);
add(temp,1);
}
cout << res1 << ' ' << res2;
}
树状数组实现差分
#include<iostream>
#include<cstring>
using namespace std;
const int N = 100010;
typedef long long ll;
int n,m;
int a[N],tr[N];
int lowb(int x){
return x & -x;
}
void add(int pos,int x){
for(int i = pos;i <= n;i += lowb(i)) tr[i] += x;
}
ll sum(int pos){
ll res = 0;
for(int i = pos;i;i -= lowb(i)) res += tr[i];
return res;
}
int main(){
cin >> n >> m;
for(int i = 1;i <= n;i ++) cin >> a[i];
for(int i = 1;i <= n;i ++) add(i,a[i] - a[i - 1]); //构造差分数组
while(m --){
string op;
cin >> op;
if(op == "Q"){
int x;
cin >> x;
cout << sum(x) << endl;
}else{
int l,r,d;
cin >> l >> r >> d;
add(l,d),add(r + 1,-d); //差分计算
}
}
}
more complex
感觉没必要,可以写线段树