MooFest(POJ-1990)(树状数组)

最近学习了一下树状数组,这道题纠结了很久,终究是因为没有明白树状数组怎么用。

感觉网上许多大神都只是讲原理,对于我们这些初学的菜鸟恐怕都被吓跑了。

这里我就以实用主义说一下使用方法(其实我觉得其原理应该能对我们更有启发,也许会带来很多潜在的好处):

这里需要注意的是,bit的实现代码中的bit数组一开始必须清零,这个数组并不是用来储存元素的,而是为实现这个数据结构而存在的。  你需要存储的元素是要通过那个add函数添加的,而求和则是要通过sum函数实现的,而这个bit数组的结构并不是对于一个新手很容易理解的,我们也大可不必关心这个。

另外要注意一个地方,在add函数里那个n,要开的足够大,不然你是添加不进去的,比如你要是把n=10,求sum(100) 会得到0 。

举个例子: 输入n个元素,求前n个元素的和。代码如下

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int bit[1000],n;
int sum(int i) {
    int s = 0;
    while(i>0) {
        s+=bit[i];
        i-=i& -i;
    }
    return s;
}
int add(int i,int x){
    while(i <= n){
        bit[i] += x;
        i += (i & -i);
    }
}
int main() {
    while(~scanf("%d",&n)) {
        memset(bit,0,sizeof(bit));
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            add(i,x);
        }
        for(int i=1;i<=n;i++) printf("%d\n",sum(i));
    }
    return 0;
}

相信看了上面的代码就可以很清晰的明白了,第几个元素,是要输入进add函数的,你输入的i是几,那么这个元素就是树状数组中的第几个元素。与bit数组无关,这个数组只是为了实现特定的数据结构而存在的辅助函数罢了。

该题代码是参考了别人的。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const int max_n = 20000+4;
ll cnt_bit[20005]={0},distance_bit[20005]={0};
int n;
struct point {
    int  v,x;
}a[20005];
bool cmp(point a,point b) {
    return a.v<b.v;
}
ll  sum_(ll *bit,int i) {
    ll s = 0;
    while(i>0) {
        s+=bit[i];
        i-=i & -i;
    }
    return s;
}
ll sum(ll *a,int i,int j) {
    return sum_(a,j-1) - sum_(a,i-1);
}
void add(ll *bit,int i,int x) {
    while(i<=max_n) {
        bit[i] += x;
        i += i&-i;
    }
}
int main() {
    ll tot = 0;
    scanf("%d",&n);
    memset(cnt_bit,0,sizeof(cnt_bit));
    memset(distance_bit,0,sizeof(distance_bit));
    for(int i=0;i<n;i++) scanf("%d%d",&a[i].v,&a[i].x);
    sort(a,a+n,cmp);
    for(int i=0;i<n;i++) {
        int v = a[i].v;
        int  x = a[i].x;
        ll  left = sum(cnt_bit,1,x) ;
        ll  right = sum(cnt_bit,x+1,max_n);
        tot+=((left*x-sum(distance_bit,1,x)) + (sum(distance_bit,x+1,max_n)-right*x))*v;
        add(cnt_bit,a[i].x,1);
        add(distance_bit,a[i].x,a[i].x);
    }
    printf("%lld\n",tot);
    return 0;
}
时间: 2024-10-12 14:08:08

MooFest(POJ-1990)(树状数组)的相关文章

MooFest POJ - 1990 (树状数组)

Every year, Farmer John's N (1 <= N <= 20,000) cows attend "MooFest",a social gathering of cows from around the world. MooFest involves a variety of events including haybale stacking, fence jumping, pin the tail on the farmer, and of cours

poj 1990 树状数组

传送门:https://vjudge.net/problem/POJ-1990 题意:m头牛,每头牛有两个值v和x.然后每两头牛之间的值是abs(x1-x2) * Max(v1,v2).问所有m*(m-1)/2对牛之间值的总和. 白书上来的.就是用树状数组做.首先肯定是按照v排序,这样就可以不用管v了.接下来我们看看x. 我们先对所有牛的x排序,然后每头牛有一个idx代表这头牛的x在所有牛的x中排第几位.然后有两个树状数组,num[N]和dis[N].num[i]表示比i小的有多少个,dis[i

poj 2299 树状数组求逆序数+离散化

http://poj.org/problem?id=2299 最初做离散化的时候没太确定但是写完发现对的---因为后缀数组学的时候,,这种思维习惯了吧 1.初始化as[i]=i:对as数组按照num[]的大小间接排序 2.bs[as[i]]=i:现在bs数组就是num[]数组的离散化后的结果 3.注意,树状数组中lowbit(i)  i是不可以为0的,0&(-0)=0,死循环... #include <cstdio> #include <cstring> #include

POJ 2352Stars 树状数组

Stars Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 42898   Accepted: 18664 Description Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a st

SYSU-5, POJ 2131, 树状数组+二分

题目大意:给出n个人,顺序对位置进行请求,如果第i个人请求的位置上有人,则让这个人顺延,如果顺延的位置继续有人,递归进行,问最后所有人的位置. 解:这题貌似可以用平衡树+并查集搞定,但是我队友强烈安利树状数组的做法.赛场上没出,赛后结合discuz想了一下,作一下处理. 首先如果是一个请求第a[i]个有空位置的问题,那么这个问题显然可以用树状数组维护前缀和即可.所以我们现在考虑将原问题转化成这个问题. 考虑终态,把没有人的位置去掉,剩下的n个座位排在一起,显然转化成上面模型的形式 第i个询问时,

POJ 1201 树状数组

链接: http://poj.org/problem?id=1201 题意: 给你n个区间,每个区间为[a,b],每个区间取c个数构成一个集合,求集合最小容量 题解: 把区间按b排序,从第一个区间开始取,从后往前取,这样尽可能和后面的区间重复 另外如果我们发现当前区间取得个数已经超过了c,那么只需要让之前区间换就行,而总数是不变的,所以不用更新答案 求当前区间已经取了多少个数用树状数组 代码: 1 #include <map> 2 #include <set> 3 #include

POJ 3321 树状数组(+dfs+重新建树)

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 27092   Accepted: 8033 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been

[bzoj3378][Usaco2004 Open]MooFest 狂欢节_树状数组

MooFest 狂欢节 bzoj-3378 Usaco-2004 Open 题目大意:给定一个n个数的a序列,每两个数之间有一个距离,两个点之间的权值为$max(a[i],a[j])*dis(i,j)$. 注释:$1\le n\le 2\cdot 10^4$. 想法:裙子说了,这种$max$和$min$的题通常要枚举这个$max$和$min$到底是多少. 这样的话我们就将所有点按权值从大到小排序. 往树状数组里插. 查询直接查询即可. 最后,附上丑陋的代码... ... #include <io

[BZOJ3378] [Usaco2004 Open]MooFest 狂欢节(树状数组)

传送门 开2个树状数组 一个存的是下标,一个存的是数量 细节...看标称吧,懒得说了,好气啊 #include <cstdio> #include <iostream> #include <algorithm> #define N 20001 #define LL long long #define max(x, y) ((x) > (y) ? (x) : (y)) int n, m; LL ans, sum, c[N], d[N]; struct node {

poj 2182 树状数组

倒着考虑,如果最后一只牛的前面有x只比它小,那么它就是第x+1只牛,从序列中去掉它.对倒数第二只牛来说也同理.可以用树状数组来维护前缀和,一开始每个位置都是1,求出结果的牛从树状数组中删掉(update成0),即可获得答案. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 8001; 7 int c[N]; 8