当前位置: 首页 > news >正文

树状数组区间更新+区间查询+单点查询

为了更好地使用复杂度比线段树更加优化的树状数组,所以必须实现树状数组的区间更新;树状数组时间复杂度为O(MlogN), 实际用的时候优于线段树,且写得少。

 

区间更新、单点查询

引入差分数组,假设初始数据数组为a,另a[0] = 0;设要维护的差分数组为 d[i] = a[i] - a[i-1];进一步可知 a[i] = d[1] + d[2] + ... + d[i]; 即前i项和,为方便记为sigma(d, i);例如如下例子:

a:1 2 3 5 6 9

d:1 1 1 2 1 3

如果进行区间[2, 5]更新加2,则:

a:1 4 5 7 8 9

d:1 3 1 2 1 1

会发现当某个区间[x, y]内值发生了同等改变,但这个区间内的差值还是不变的,只有d[x]和d[y+1]的值发生了改变。

所以可以建立区间更新、单点查询的树状数组去维护d[],例如如下例子:

d:1 1 1 2 1 3

c:1 2 1 5 1 4(c值如何计算参考下图)

区间[2, 5]更新加2,则:

d:1 3 1 2 1 1

c:1 4 1 7 1 2(c值如何计算参考下图)

int lowbit(int k){
	return k & -k;
}

void update(int n, int *c, int i, int va){
	while(i <= n){
		c[i] += va;
		i += lowbit(i);
	}
}

int pointValue(int *c, int i) {
    int res = 0;
    while(i > 0){
        res += c[i];
        i -= lowbit(i);
    }
    return res;
}

//-------------------------------------

// 在区间[x, y]增加k
updata(n, c, x, k);   
updata(n, c, y+1, -k);

// 获得第i点的值
pointValue(c, i);

区间更新、区间查询

根据差分数组:

sum[n]

= a[1] + a[2] + .. + a[n];

sigma(d, 1) + sigma(d, 2) + ... + sigma(d, n);

= n*d[1] + (n-1)*d[2] + ... + 2*d[n-1] + 1*d[n];

n*(d[1] + d[2] +...+ d[n]) - (0*d[1] + 1*d[2] + ... + (n-1)*d[n]);

所以可以得到 sum[n] =n * sigma(d, n)  - (0*d[1] + 1*d[2] + ... + (n-1)*d[n]);

令r[i] = (i-1) * d[i];

则 sum[n] = n * sigma(d, n) - sigma(r, n);

此时则需要构造两个树状数组去分别维护d[]和r[]的更新;例如如下例子:

a:  1 2 3 5 6 9

d:  1 1 1 2 1 3

c1:1 2 1 5 1 4

r:   0 1 2 6 4 15

c2:0 1 2 9 4 19

如果进行区间[2, 5]更新加2,则:

a:  1 4 5 7 8 9

d:  1 3 1 2 1 1

c1:1 4 1 7 1 2

r:   0 3 2 6 4 5

c2:0 3 2 11 4 9

注:c1、c2的计算过程同样参考上图。
注意c2更新前后,其在区间左端点2处开始向后更新加k*(2-1),在右端点5再加1=6处,更新减k*(5-1)。

代码如下:

int lowbit(int k){
	return k & -k;
}

void update(int n, int *c1, int *c2, int i, int va){
    int x = i;
	while(i <= n){
		c1[i] += va;
		c2[i] += va * (x-1);
		i += lowbit(i);
	}
}

int sum(int *c1, int *c2, int i) {
    int res = 0, x = i;
    while(i > 0){
        res += x * c1[i] - c2[i];
        i -= lowbit(i);
    }
    return res;
}

//-------------------------------------

// 在区间[x, y]增加k
updata(n, c, x, k);   
updata(n, c, y+1, -k);

// 获得[x, y]的和
res = sum(c1, c2, y) - sum(c1, c2, x-1);

 

其它细节可参考:https://www.cnblogs.com/xenny/p/9739600.html

相关文章:

  • PHPCMS如何实现后台访问限制?
  • 树的直径 —— 即一棵树的最长路 附题(大臣的旅费 by蓝桥杯)
  • 一个关于按位或的故事~~(QDU-码农必修)
  • ConcurrentHashMap 解读(一)
  • Today一只菜鸡的PAT甲级测试(PAT1124, PAT1125, PAT1126, PAT1127)
  • 快速排序--自行实现+qsort+sort
  • 归并排序--二路归并
  • quartz定时任务时间设置描
  • ctype.h头文件中的tolower和toupper以及cctype其他函数的应用
  • mbr损坏以及grub.conf的配置文件丢失或出错的方法
  • 单链表的基本操作
  • 抽象类与接口的区别
  • 不常用的模拟链表
  • Floyed-Warshall-求最短路
  • Server should be SSL-aware but has no certificate
  • Angular数据绑定机制
  • Docker容器管理
  • docker容器内的网络抓包
  • extjs4学习之配置
  • Hibernate【inverse和cascade属性】知识要点
  • iOS | NSProxy
  • JS+CSS实现数字滚动
  • log4j2输出到kafka
  • PHP 7 修改了什么呢 -- 2
  • python docx文档转html页面
  • Python学习之路16-使用API
  • SwizzleMethod 黑魔法
  • 关于for循环的简单归纳
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 用Python写一份独特的元宵节祝福
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • #vue3 实现前端下载excel文件模板功能
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (a /b)*c的值
  • (二)hibernate配置管理
  • (分类)KNN算法- 参数调优
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (七)c52学习之旅-中断
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (转) ns2/nam与nam实现相关的文件
  • (转)memcache、redis缓存
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET Reactor简单使用教程
  • .net 程序发生了一个不可捕获的异常
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • @Autowired 与@Resource的区别
  • @JSONField或@JsonProperty注解使用
  • @JsonFormat与@DateTimeFormat注解的使用
  • @RequestParam,@RequestBody和@PathVariable 区别
  • @Validated和@Valid校验参数区别
  • [ C++ ] STL---stack与queue
  • [2016.7 test.5] T1