利用上面的性质,在树状数组的尾部插入数据,来建立一个树状数组
void push(int pos){
int i,lb = lowbit(pos);
c[pos] = a[pos];
for(i=1;i<lb;i <<=1){
c[pos] = max(c[pos],c[pos-i]);
}
}
void update(int pos,int v){
int i,lb;
c[pos] = a[pos] = v;
lb = lowbit(pos);
for(i=1;i<lb;i <<=1){ //利用孩子更新自己
c[pos] = c[pos] > c[pos-i] ? c[pos] : c[pos-i];
}
int pre = c[pos];
pos+=lowbit(pos);//父亲的位置
/* 更新父亲 */
while(pos <= n){
if( c[pos] < pre){ //更新的父亲
c[pos] = pre;
pos +=lowbit(pos);
} //没有更新父亲
else break;
}
}
设 query(x,y)query(x,y) 求区间 [x,y] 之间的最值, 已知 c[x] 表示 [x−lowbit(x)+1,x] 之间的最值,那如何求区间 [x,y] 的最值呢?
我们不难发现:
所以,我们发现下面的规律,因为 y−lowbit(y)+1y−lowbit(y)+1 表示 c[y]c[y] 结点所管辖范围的最左边的点若
query(x,y)=max(c[y],query(x,y−lowbit(y)))query(x,y)=max(c[y],query(x,y−lowbit(y)));
int query(int x,int y){
int res = -1;
while(x <= y){
int nx = y - lowbit(y)+1; //最左边的点
if(nx >= x ){
res = res < c[y] ? c[y] :res; //判断是否最优
y = nx-1; // 下一个求解区间
} else { // nx < x
res = res < a[y] ? a[y] :res; //判断是否最优
y--;
}
}
return res;
}
特点:
所以,树状数组求区间最值特别适合那些:一边在尾部添加数据,一边查询的题目
const int maxn = 1e6 + 5, maxe = 1e6 + 5; //点与边的数量
int n, m;
int N = maxn;
int a[maxn], c[maxn]; // a是原数组
inline int lowbit(int x) { return x & -x; }
inline int fa(int p) { return p + lowbit(p); }
inline int left(int p) { return p - lowbit(p); }
inline int g(int a, int b) { return a>b ? a : b; }
void update_by_child(int p, int v) { //alias push
c[p] = a[p] = v;
int lb = lowbit(p);
for (int i = 1; i < lb; i <<= 1)
c[p] = g(c[p], c[p - i]);
}
void update(int p, int v) {
update_by_child(p, v);
int t = c[p];
for (p = fa(p); p <= N; p = fa(p)) {
if (g(t, c[p])) c[p] = t;
else break;
}
}
int query(int l, int r) { // 求区间最值
int ret = a[l];
for (; l <= r; ) {
int next = left(r) + 1;
if (next >= l) ret = g(ret, c[r]), r = next - 1;
else ret = g(ret, a[r]), r--;
}
return ret;
}
思路: 利用树状数组求区间最值
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5, maxe = 1e6 + 5; //点与边的数量
int n, m;
int N = maxn;
int a[maxn], c[maxn]; // a是原数组
inline int lowbit(int x) { return x & -x; }
inline int fa(int p) { return p + lowbit(p); }
inline int left(int p) { return p - lowbit(p); }
inline int g(int a, int b) { return a>b ? a : b; }
void update_by_child(int p, int v) { //alias push
c[p] = a[p] = v;
int lb = lowbit(p);
for (int i = 1; i < lb; i <<= 1)
c[p] = g(c[p], c[p - i]);
}
void update(int p, int v) {
update_by_child(p, v);
int t = c[p];
for (p = fa(p); p <= N; p = fa(p)) {
if (g(t, c[p])) c[p] = t;
else break;
}
}
int query(int l, int r) { // 求区间最值
int ret = a[l];
for (; l <= r; ) {
int next = left(r) + 1;
if (next >= l) ret = g(ret, c[r]), r = next - 1;
else ret = g(ret, a[r]), r--;
}
return ret;
}
int main() {
while (1) {
memset(a, 0, sizeof(a));
memset(c, 0, sizeof(c));
if (scanf("%d%d", &n, &m) == EOF) break;
for (int i = 1; i <= n; ++i) {
int t;
scanf("%d", &t);
update_by_child(i, t); //初始化原数组与树状数组
}
char s[10];
for (int i = 1; i <= m; ++i) {
scanf("%s", s);
int x, y;
if (s[0] == 'Q') {
scanf("%d%d", &x, &y);
ll ans = query(x, y);
printf("%lld\n", ans);
}
else {
scanf("%d%d", &x, &y);
update(x, y);
}
}
}
return 0;
}