博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树状数组总结
阅读量:6833 次
发布时间:2019-06-26

本文共 1856 字,大约阅读时间需要 6 分钟。

树状数组总结

对于树状数组,基本操作有以下两种

int sum(int x){   int ret=0;   while(x>0){     ret+=C[x];     x-=lowbit(x);   }   return ret; }void add(int x,int d){    while(x<=n){    C[x]+=d;    x+=lowbit(x);    }}

对于树状数组,代码功能其实不难理解,主要是对于操作利用要灵活,选取多个习题进行练习是个不错的选择

树状数组基本操作

习题1:

  • 题意:n个人,现在需要这样的三人集合:中间的人技能值处在左右两个人的技能值之间,问存在多少个这样的集合。
  • 解法:设l[i]为i左边小于a[i]的人数,r[i]为大于其的人数,答案为
for i:1~n   ans+=l[i]*r[i]+(i-1-l[i])*(n-i-r[i]);

重点在于对l[i]和r[i]的计算

memset(C,0,sizeof(C));for(int i=1; i<=n; i++){    l[i]=sum(a[i]-1);    add(a[i],1);}memset(C,0,sizeof(C));for(int i=n; i>=1; i--){    r[i]=n-i-sum(a[i]);    add(a[i],1);}

习题2:

  • 题意:对于一个数列(1~n乱序),每次把最前面的一个数放到数列最后面,求所有这样的操作中逆序数最少时是多少
  • 解法:首先求出现有数列的逆序数之和ans,然后每个a[i]移至数列之尾对ans的影响为ans=ans-(n-a[i])+(a[i]-1),枚举即可得到答案

(现有逆序数之和怎么求?)

for i:1~nans+=sum(a[i]+1);  //sum(a[i])求在i之前比a[i]大的数字个数add(a[i],1);

通过前两题,可以说对树状数组的基本操作有了个认识,现在可以进行更高层次的训练

树状数组+离线处理

习题1:

  • 题意:一串珠子,每个珠子有一个值,query(l,r)是问l到r之间珠子的值之和,同时相同的值只计数一次,如 1 2 1,query(1,3)=3

  • 解法:

不如结合案例进行分析如下原数列为:2,3,4,3我们对所有的(n)*(n-1)/2个(l,r)区间进行推算1. (l,1)    -->      query(1,1)=2; 2. (l,2)   -->      query(1,2)=5;      query(2,2)=3;  3. (l,3)   -->      query(1,3)=9;      query(2,3)=7;      query(3,3)=4;4. (1,4)    -->      query(1,4)=9;  //注意到此处      query(2,4)=7;  //注意到此处      query(3,4)=7;      query(4,4)=3;
很显然,前三组数据都可以使用树状数组直接求出,只有到第四组数据的时候会出现误差,然而这样的差错在按照r按顺序排列查询是可以避免的。只要我们在新出现的数字出现时判断之前是否已经出现过,如果出现,就把之前的那个位置清空,在新的下标上加上这个数字。

Q:只将r端点进行排序,l端点出现的顺序对答案有没有影响?

Ans:没有,我们只需要计算a[r]这个数字一次就行了,更新的这个数字顶多也就是a[r]这个位置的数,对l的数字没有任何影响

sort(b+1,b+m+1,cmp1);    //按r从小到大排序int q=1;for(int i=1; i<=n&&q<=m; i++){    if(book[a[i]]) add(book[a[i]],-a[i]);    add(i,a[i]);    book[a[i]]=i;    while(b[q].r==i)    {        b[q].ans=sum(b[q].r)-sum(b[q].l-1);        q++;    }}sort(b+1,b+m+1,cmp2);     //按id从小到大排序for(int i=1; i<=m; i++){    printf("%lld\n",b[i].ans);}

转载于:https://www.cnblogs.com/zsyacm666666/p/6544359.html

你可能感兴趣的文章
java jvm学习笔记十(策略和保护域)
查看>>
Linux(CentOS)挂载移动硬盘
查看>>
JaveWeb 公司项目(7)----- 通过JS动态生成DIV
查看>>
python_控制台输出带颜色的文字方法
查看>>
TiDB 深度实践之旅--真实“踩坑”经历
查看>>
通过Cloudera Manager安装CDH 5.6
查看>>
Android通过JNI实现与C语言的串口通讯操作蓝牙硬件模块
查看>>
《Java实战开发经典》第五章5.3
查看>>
Codeforces Round #247 (Div. 2) D. Random Task
查看>>
在ubuntu18.04版本安装vscode
查看>>
Cracking the coding interview--Q1.8
查看>>
前端(开发环境) 5
查看>>
2017ACM/ICPC广西邀请赛 Color it
查看>>
Photoshop蒙版介绍之图层蒙版
查看>>
java通过传送地址获取坐标
查看>>
10个Python练手小程序,学习python的很好的资料
查看>>
Linux终端快捷键
查看>>
乐观锁与悲观锁
查看>>
docker windows container的一些注意点
查看>>
拥抱博客园
查看>>