洛谷P1428 树状数组。。。
2016-05-13 15:27
337 查看
数据有点水先放一个水点的代码,不水的思路放后面
既然标签都写了树状数组~那就用树状数组写就好了。。。
具体树状数组是啥~不知道的同学可以查一下。。大概的意思是用数组的和做出一个树
大概的思路就是A数组表示每种数有多少个
比如数据是 4 4 3 2 1 那么a[4] = 2,a[3] = 1,a[2]=1,a[1] =1
然后每次只需要找一下对应的C数组就好了
具体模拟一下样例吧
4 3 0 5 1 2
第一步:输入4 此时a数组为 0 0 0 0 1 0 0 0 … (有一个4,所以a[4] = 1)然后计算一下a[0]+a[1]+a[2]+a[3]=0,然后第一个结果就是0
第二步:输入3 此时a数组为 0 0 0 1 1 0 0 0 … 计算一下a[0]+a[1]+a[2]=0,输出0
第三步:输入0 此时a数组为 1 0 0 1 1 0 0 0 … 输出0
第四步:输入5 此时a数组为 1 0 0 1 1 0 0 0 … 计算a[0]+…+a[4] = 3,输出3
….
所以结果就出来了
但是树状数组再操作的时候不对原来的a数组操作,而是对求和的c数组进行操作,而且C数组的第一位不能为0,所以把角标往后窜一位。。于是就变成了
a[3]代表有几个2 ,a[4]代表有几个3。。。
那上边的第二步来举例,就变成 输入3,之后a数组就是 0 0 0 0 1 1 0 0….计算计算一下a[1]+a[2]+a[3]=0,输出0
所以每次输入x,结果就是sum(x), 然后维护一遍树就可以了。。(输入3,所以a[4]要加1, 于是就变成了add(x+1))
代码如下
好吧~有的人可能会问 大哥 你这个数据如果我输入是99999999,难道你要开这么大的空间吗。。。
是的。。这个就是开头说的数据水过的问题。。
对于这个问题,解决方案是~~先进行一次快排,~(千万别用n^2的排序。。。那样的话你还不如直接写俩循环做呢。。)
排序完之后重新赋值,根据大小把值都变成1~n的数,然后再进行上面的操作就好了。。
既然标签都写了树状数组~那就用树状数组写就好了。。。
具体树状数组是啥~不知道的同学可以查一下。。大概的意思是用数组的和做出一个树
大概的思路就是A数组表示每种数有多少个
比如数据是 4 4 3 2 1 那么a[4] = 2,a[3] = 1,a[2]=1,a[1] =1
然后每次只需要找一下对应的C数组就好了
具体模拟一下样例吧
4 3 0 5 1 2
第一步:输入4 此时a数组为 0 0 0 0 1 0 0 0 … (有一个4,所以a[4] = 1)然后计算一下a[0]+a[1]+a[2]+a[3]=0,然后第一个结果就是0
第二步:输入3 此时a数组为 0 0 0 1 1 0 0 0 … 计算一下a[0]+a[1]+a[2]=0,输出0
第三步:输入0 此时a数组为 1 0 0 1 1 0 0 0 … 输出0
第四步:输入5 此时a数组为 1 0 0 1 1 0 0 0 … 计算a[0]+…+a[4] = 3,输出3
….
所以结果就出来了
但是树状数组再操作的时候不对原来的a数组操作,而是对求和的c数组进行操作,而且C数组的第一位不能为0,所以把角标往后窜一位。。于是就变成了
a[3]代表有几个2 ,a[4]代表有几个3。。。
那上边的第二步来举例,就变成 输入3,之后a数组就是 0 0 0 0 1 1 0 0….计算计算一下a[1]+a[2]+a[3]=0,输出0
所以每次输入x,结果就是sum(x), 然后维护一遍树就可以了。。(输入3,所以a[4]要加1, 于是就变成了add(x+1))
代码如下
#include<stdio.h> int n; int treearray[101]; int lowbit(int x) { return x&(-x); } void add(int x) { while (x <= 100) { treearray[x]++; x += lowbit(x); } } int sum(int x) { int ans = 0; while (x > 0) { ans += treearray[x]; x -= lowbit(x); } return ans; } int main() { int i; int x; for (i = 0; i < 101; i++) { treearray[i] = 0; } scanf("%d", &n); for (i = 0; i < n; i++) { scanf("%d", &x); //这是排格式。。。 if (i == 0) printf("%d", sum(x));//每次输入一个值,计算他之前的和 else printf(" %d", sum(x)); add(x+1); } printf("\n"); return 0; }
好吧~有的人可能会问 大哥 你这个数据如果我输入是99999999,难道你要开这么大的空间吗。。。
是的。。这个就是开头说的数据水过的问题。。
对于这个问题,解决方案是~~先进行一次快排,~(千万别用n^2的排序。。。那样的话你还不如直接写俩循环做呢。。)
排序完之后重新赋值,根据大小把值都变成1~n的数,然后再进行上面的操作就好了。。
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- Lua和C语言的交互详解
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法