http://poj.org/problem?id=2352

http://acm.zstu.edu.cn:8080/JudgeOnline/showproblem?problem_id=3106

(1)解题时想用上线段树,题中数据已经排好序了,排序以 y 为主,以 x 为辅。而每颗星星的等级是两个坐标均不大于该星星的总数目(不包括自己),

   所以 y 的值是“无用的数据”。只需要知道有多少个其他星星的 x 小于该星星自身的 x  ,即为该星星的等级数。可以用线段树加速这个过程。

(2)第一种方法用的不是线段树:

   1)神奇的位运算:

int lowbit(int x)
{
    return x&(-x);
}

     返回该数二进制下的最低位非零位所对应的值(尝试输出 x 从1到9的结果,均为

     2的幂次)。

   2)优化了的 count 数组。数组中count[1<<i] 表示的是不大于1<<i 的星星个数。

     其他零散的 count 记录的是剩余的“遗漏值”(较难理解,细细体会)。

   3)计算各个星星的级数时,用二进制一一去处尾部的非零位,以便于收集零散值。 

   3)未解的疑惑:评级、更新为什么要从 x+1 开始?

     若从 x 开始,案例可以通过,但是会超时。

(3)很基本的线段树:

     1)之所以没有想通,是因为不会用线段树完成星星的评级。设置变量 grade ,

             记录的是星星的现有级数。本质上是最底层的 sum 的加和(这个和的加和

     是最大的难点难点)。对 grade 的处理是核心要素,详见代码二。

   2)长度默认为 N 。

方法一具体代码:

View Code
#include<stdio.h>
#include<string.h>
const int N=32000+10;
int count[N], level[N];
int n;
int lowbit(int x)
{
    return x&(-x);
}
int grade(int x)
{
    int sum=0;
    while(x>0)
    {
        sum+=count[x];
        x-=lowbit(x);
    }
    return sum;
}
void update(int x)
{
    while(x<N)
    {
        count[x]++;
        x+=lowbit(x);
    }
}
int main()
{
    int i, j;
    while(scanf("%d", &n)!=EOF)
    {
        memset(count,0 ,sizeof(count));
        memset(level, 0, sizeof(level));
        for(i=1;i<=n;i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            level[grade(x+1)]++;
            update(x+1);
        }
        for(i=0;i<n;i++)
            printf("%d\n", level[i]);
    }
    return 0;
}

方法二具体代码:

View Code
#include<stdio.h>
#include<string.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int N=32200;
int sum[N<<2], level[N];
int n;
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int p, int grade, int l, int r, int rt)
{
    if(l==r)
    {
        level[grade+sum[rt]]++;
        sum[rt]++;
        return ;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p, grade, lson);
    else update(p, grade+sum[rt<<1], rson);
    pushup(rt);
}
int main()
{
    int i, j;
    int x, y;
    while(scanf("%d", &n)!=EOF)
    {
        memset(sum, 0, sizeof(sum));
        memset(level, 0, sizeof(level));
        for(i=1;i<=n;i++)
        {
            scanf("%d%d", &x, &y);
            update(x, 0, 0, N-1, 1);
        }
        for(i=0;i<n;i++)
            printf("%d\n", level[i]);
    }
    return 0;
}