树状数组(2)

来源:互联网 发布:事业单位域名注册 编辑:程序博客网 时间:2024/05/16 10:35

一维树状数组的应用

poj 2352 stars

题意:在整数坐标0<=x,y<=32000上有很多星星
每颗星的level(级别)值 等于 不比它高不比它右的星星数目
给出每颗星星的坐标。求每个level的星星数目。

学过的同志们一定会会心地一笑了,没有做过的同志们肯定也懵逼了(内心独白:what?这跟树状数组有何关系?)
noip式懵逼

其实大家
细心的我已经把图给挖下来了

算法分析:
好像要所有数据读入之后才一个个问,其实不然,我们可以采取一边读数据一边统计的方法
(注意了,输入格式已经给出:星星按 Y 的升序给出,Y 相等则按 X 的升序给出)。
也是就是当前的第i个星星读入坐标的时候其实它的级别已经确定了,因为后面的星星不会让星星i升级的,
(因为星星是按Y升序给出的,所以后面的星星不会比当前星星i低,最多同高,但因为同高的星星是从左到右给出的,所以后面的星星不会在当前星星i的左边。)
所以我们只需要 关注 每颗星星的x坐标,统计 1~x[i]有多少个值出现过,出现过的点为1,那么我们就可以统计了。

代码:

#include <cstdio>#include <cstring>using namespace std;int c[32010],l[32010],n;int lowbit(int x){    return x&-x;}void add(int x,int y){    while (x<=32005)    {        c[x]+=y;        x+=lowbit(x);    }}int getsum(int x){    int s=0;    while (x>=1)    {        s+=c[x];        x-=lowbit(x);    }    return s;}int main(){    int x,y;    while (scanf("%d",&n)!=EOF)    {        memset(c,0,sizeof(c));        memset(l,0,sizeof(l));         for (int i=1;i<=n;i++)        {            scanf("%d%d",&x,&y);            add(x+1,1);            l[getsum(x+1)]++;        }        for (int i=1;i<=n;i++)            printf("%d\n",l[i]);    }}

stars的拓展:
poj2481 cows

看到这道题,做过的同志们肯定又要偷笑了,没看过的同志们又接着懵逼了

题意:
一条线上有很多不同长度的线段【s,e】,代表了不同牛的领域范围。如果Si <= Sj 并且 Ej <= Ei 并且 Ei - Si > Ej - Sj 就说明母牛i比母牛j强壮。对于每一头牛,有多少头牛比他强壮?

算法分析:
我们可以把这一条线段扩大成一片草地(类似平面直角坐标系的东东),将每头母牛的领域范围线段【s,e】变为一个在平面直角坐标系上的点【s,e】。画一画图,是不是和上面的stars很像咧?只需要变动一下(注意:stars是求他左下方有多少个点,而这一题则是求他的左上方有多少个点)。
值得提醒一下的是:这一题的数据是无序给出的,我们需要预先排序。

0 0