【进阶——树状数组】 区间求最值
2015-11-28 13:28
316 查看
上一篇讲的是区间求和,这一篇讲区间求最值。
首先,a[]数组仍然是保存原始数据。但是c[]数组变了,c[i]将会保存从a[1]到a[i]的最值。
初始化c[]:
当我们输入a[i]时,c[i]需要需要向前依次枚举被c[i]所包含的c[]数组。比如,当i == 8时,需要向前依次枚举c[7], c[6], c[4],取a[8]与这几个c[]中的最值保存在c[8]中。找到c[]的规律了没有?依次是i-1, i-2, i-4...
可以看出,每输入一个a[i],处理c[i]的时间复杂度为log2(n),输入n个,初始化的时间复杂度就是n*log2(n)。
修改c[]:
我们改变了一个a[i],那么就需要修改所有与a[i],相关的c[]。修改每个的c[]的方法可以用上面初始化的方法,而需要修改的c[]可以用区间求和里的一段代码确定。
每次修改的时间复杂度近似为log2(n)*log2(n)。
查询:
查询从a[i]到a[j]之间的最值(i <= j)。我们不能直接查看c[j],因为也许c[j]中包含的区间[l, r]中l < i或l > i,c[j]不能恰好包含区间[i, j]。
因此,当l < i时,我们就取a[j]与当前已经取到的最值比较,如果a[j]满足取代条件,就用a[j]取代当前最值。
当l >= i,我们取c[j]与当前最值比较,如果c[j],满足取代条件,就用c[j]取代当前最值。
当l == i时,比较结束。
时间复杂度近似为log2(n)。
mod
树状数组区间求和——
/article/5857189.html
首先,a[]数组仍然是保存原始数据。但是c[]数组变了,c[i]将会保存从a[1]到a[i]的最值。
初始化c[]:
当我们输入a[i]时,c[i]需要需要向前依次枚举被c[i]所包含的c[]数组。比如,当i == 8时,需要向前依次枚举c[7], c[6], c[4],取a[8]与这几个c[]中的最值保存在c[8]中。找到c[]的规律了没有?依次是i-1, i-2, i-4...
void Init() { int y; memset(c, 0, sizeof(c)); for(int i = 1; i <= n; i++) { scanf("%d", &y); a[i] = y; c[i] = y; for(int j = 1; j <lowbit(i); j <<= 1) //需要比较的c[] c[i] = c[i] > c[i-j] ? c[i] : c[i-j]; } }
可以看出,每输入一个a[i],处理c[i]的时间复杂度为log2(n),输入n个,初始化的时间复杂度就是n*log2(n)。
修改c[]:
我们改变了一个a[i],那么就需要修改所有与a[i],相关的c[]。修改每个的c[]的方法可以用上面初始化的方法,而需要修改的c[]可以用区间求和里的一段代码确定。
void Maxn(int x, int y) { a[x] = y; for(int i = x; i <= n; i += lowbit(i)) //需要修改的c[] { c[i] = y; for(int j = 1; j < lowbit(i); j <<= 1) //修改时需要比较的c[] { c[i] = c[i] > c[i-j] ? c[i] : c[i-j]; } } }
每次修改的时间复杂度近似为log2(n)*log2(n)。
查询:
查询从a[i]到a[j]之间的最值(i <= j)。我们不能直接查看c[j],因为也许c[j]中包含的区间[l, r]中l < i或l > i,c[j]不能恰好包含区间[i, j]。
因此,当l < i时,我们就取a[j]与当前已经取到的最值比较,如果a[j]满足取代条件,就用a[j]取代当前最值。
当l >= i,我们取c[j]与当前最值比较,如果c[j],满足取代条件,就用c[j]取代当前最值。
当l == i时,比较结束。
void Query(int l, int r) { int ans = 0; while(1) { ans = ans > a[r] ? ans : a[r]; if(r == l) break; for(r -= 1; r-l >= lowbit(r); r -= lowbit(r)) ans = ans > c[r] ? ans : c[r]; } printf("%d\n", ans); }
时间复杂度近似为log2(n)。
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int N = 200010; int a , c ; int t, n, m; int lowbit(int x) { return x&(-x); } void Maxn(int x, int y) { a[x] = y; for(int i = x; i <= n; i += lowbit(i)) //需要修改的c[] { c[i] = y; for(int j = 1; j < lowbit(i); j <<= 1) //修改时需要比较的c[] { c[i] = c[i] > c[i-j] ? c[i] : c[i-j]; } } } void Init() { int y; memset(c, 0, sizeof(c)); for(int i = 1; i <= n; i++) { scanf("%d", &y); a[i] = y; c[i] = y; for(int j = 1; j <lowbit(i); j <<= 1) //需要比较的c[] c[i] = c[i] > c[i-j] ? c[i] : c[i-j]; } } void Query(int l, int r) { int ans = 0; while(1) { ans = ans > a[r] ? ans : a[r]; if(r == l) break; for(r -= 1; r-l >= lowbit(r); r -= lowbit(r)) ans = ans > c[r] ? ans : c[r]; } printf("%d\n", ans); } void Work() { char s[2]; int x, y; for(int i = 1; i <= m; i++) { scanf("%s%d%d", s, &x, &y); if(s[0] == 'U') Maxn(x, y); else if(s[0] == 'Q') Query(x, y); } } int main() { //freopen("test.in", "r", stdin); while(~scanf("%d%d", &n, &m)) { Init(); Work(); } }
mod
树状数组区间求和——
/article/5857189.html
相关文章推荐
- javascript加密之md5加密
- 近似装箱问题(三种联机算法实现)
- 【转载】一个将string转换为 const* char的函数
- Android应用程序换肤实现系列(四)
- React使用笔记(3)-React Event Listener
- 安卓属性获取
- 树套树学习
- Android接收和发送短信
- iOS MRC手动内存管理 心得体会
- 阅读腾讯编程规范的笔记
- 在一个Activity里更新另一个Activity UI
- 关于nginx的master进程可worker进程的概念
- Servlet中转发和重定向的路径问题以及表单提交路径问题
- [No00005A]word多文档合一
- Essence and accidents of software engineering(软件工程的本质和附加属性)
- Android-读写内外部存储数据,SharePreference,PreferenceActivity,SQLite
- Swift iOS 9通讯录访问
- hbase手动compact与split
- sqlite的日期类型
- 11天学会AU3