树状数组的两道基本题
来源:互联网 发布:dvr监控软件下载 编辑:程序博客网 时间:2024/05/22 14:56
上个周学习了树状数组,但是没有怎么听懂,今天学习了线段树,较树状数组更好理解一些,弄懂了线状树之后,重看树状数组,感觉懂了一些。
我认为这两种方法都是将二分巧妙地运用在搜索的过程中,只不过方向相反,线状树是不断二分的过程,树状数组是不断拼凑出树的过程(将来深入理解之后说不定会推翻现在的想法,那谁知道呢,哈哈)。
今天先说树状数组。有两道题帮助我理解。
题一敌兵布阵,题二Stars
题一属于比较中规中矩的题,题二属于需要拐点小弯的题,两者都是完完整整的树状数组,lowbit,getsum,add都写上就可以出答案的那种。
具体的这三个函数都可以干什么就先不解释了,因为我现在也是一知半解,等到真的可以融会贯通的时候再写一篇总结吧。
敌兵布阵树状数组版代码
#include<iostream>using namespace std;#include<algorithm>#include<string.h>#include<string>const int N = 500010;int c[N];int lowbit(int x)//lowbit函数的作用就是让二进制数所有的高位1都消失,只留下最低位数的1,那其实像2,4,8这种//数字,lowbit完了还是本身{ return x&-x;}int getsum(int i)//生成前缀和{ int s = 0; while (i > 0) { s += c[i]; i = i - lowbit(i); } return s;}void add(int i, int k)//添加或者说是更新需要维护的数组,但其实需要维护的数组并不存在,重要的是要修改c数组{ while (i <= N) { c[i] += k; i += lowbit(i); }}int main(){ int t; scanf("%d", &t); int p; for (p = 1; p <= t; p++) { memset(c, 0, sizeof(c)); int n; scanf("%d", &n); int i; for (i = 1; i <= n; i++)//树状数组是不能从0开始的这个要注意 { int a; scanf("%d", &a);//输入记得用scanf add(i, a); } cout << "Case " << p << ":\n"; string order; while (cin >> order) { if (order == "End") break; int x, y; scanf("%d%d", &x, &y);//输入记得用scanf if (order == "Query") cout << getsum(y) - getsum(x - 1)<<endl;//因为是两个之间的数组,所以要用大的减去小的。 if (order == "Add") add(x, y); if (order == "Sub") add(x, -y); } } return 0;}
星星那道题的题意很重要,首先输入时有规律的,先按照y的升序输入,如果y是一样的,那么久按照x的升序输入,那么就可以忽略y坐标,相当于把一个二维的坐标面压成一个一维的坐标轴,因为每一次输入一个点的坐标的时候,都不存在y比他大的,只需要找出x比他小的就可以得出结论,那么每次输入,其实就是把要维护的a数组的相应的位置的值+1,这个题的输入是从0开始的,而树状数组是不能处理0的,所以每一个都要+1处理,大佬说这启示我们,有的时候二维的东西可以先排序,然后化成一维的问题来解决!
Stars代码
#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>using namespace std;const int MAXN=15010;const int MAXX=32010;int c[MAXX];//树状数组的c数组int cnt[MAXN];//统计结果int lowbit(int x){ return x&(-x);}void add(int i,int val){ while(i<=MAXX) { c[i]+=val; i+=lowbit(i); }}int sum(int i){ int s=0; while(i>0) { s+=c[i]; i-=lowbit(i); } return s;}int main(){ int n; int x,y; while(scanf("%d",&n)!=EOF) { memset(c,0,sizeof(c)); memset(cnt,0,sizeof(cnt)); for(int i=0;i<n;i++) { scanf("%d%d",&x,&y); int temp=sum(x+1); cnt[temp]++; add(x+1,1); } for(int i=0;i<n;i++) printf("%d\n",cnt[i]); } return 0;}
阅读全文
0 0
- 树状数组的两道基本题
- 树状数组两种基本的模式
- 树状数组的基本函数
- 树状数组的基本写法
- 树状数组的基本操作
- 树状数组的基本运用
- 树状数组的两种运用
- poj 3067 树状数组的基本运用
- 树状数组基本操作
- 基本二维树状数组
- 逆序对的两种算法【树状数组 / 归并排序】
- 关于树状数组的两种最基本的用法
- 树状数组(基本操作)
- Hdu 1166 敌兵布阵(基本树状数组的运用)
- 树状数组的基本+运用(HDU1166-敌兵布阵)
- 1001(树状数组基本操作的合集)
- poj 1990 两颗树状数组
- 树状数组的学习
- POJ 3684 Physics Experiment——弹性碰撞
- 【转】【Unity3D】利用预设、实例化Instantiate和协程完成生成器
- Numpy(一)
- 贪心基础 最大整数
- POJ 1094 Sorting It All Out(拓扑排序 入度性质)
- 树状数组的两道基本题
- 2017.8.7 序列计数 思考记录
- 成员变量和局部变量的区别,静态变量和成员变量的区别
- 函数重载
- JVM--解析Java内存区域及数据的内存分配与线程安全之间的一些联系
- 《leetCode》:Remove Nth Node From End of List
- 2017年8月7日提高组T1 根
- C语言中的指针
- 1 0 背包问题 典型的 例题 : Bone Collector