poj2352_树状数组+离散化

本文介绍使用树状数组高效解决求解每个坐标点左侧坐标个数问题的方法。通过坐标离散化及稳定排序,将二维坐标问题转化为一维处理,实现快速查找比当前坐标小的所有坐标数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出一堆坐标点,求小于每一个坐标的坐标个数。

分析:这个题显然也不能遍历,数据太大,会超时。

从poj2299,知道树状数组可以用来求一个排列中array[i]前面小于等于array[i]的个数。

例如array[i]= 9 1 0 5 4

通过树状数组可以知道:

array[1]=9--->1   即坐标小于等于1中比9小的个数为1.

array[4]=5--->3   即坐标小于等于4中比5小的个数为3.

具体怎么求呢?2299中也说过,构建树状数组时要将array[]进行排列,然后对对应的number号进行处理,即:

1.要求原来顺序 9 1 0 5 4,前面小于等于array[i]的个数,先离散化:

 array[] 9 1 0 5 4

 numer 1 2 3 4 5

2.有小到大排序

array[]   0 1 4 5 9

number  3 2 5 4 1

3.遍历number进行处理即可。

这个题要求所有的小于某个坐标的数量,因此需要对坐标进行从小到大排序,例如:

(1,1) (5,1) (7,1) (3,3) (5,5)

y 1 1 1 3 5

x 1 5 7 3 5

题目一开始就按坐标排好序,这样找比自己小的坐标就完全转化成一维的(x轴)

x     1 5 7 3 5

ans  1 2 3 2 3

这样将x轴排序,运用上述的方法就可。

得出的getsum(3)=3表示array前三项中小于等于array[3]的个数

同理先以x轴排好序,将二维转化成y轴的一维也可以。

注意:

1.因为坐标不包括它本身,因此需要减一.

2.排序时的问题:

x       1 5 7 3 5

num   1 2 3 4 5

排序后:

x      1 3 5 5 7

num 1 4 2 5 3

这里有重复数字5,排序后必须保证稳定的。因此需要写cmp函数进行规定。

网上还有一种没有离散的做法,这是因为0<=X,Y<=32000,范围比较小,如果上限开到9999999999则必须离散化。

代码:

View Code
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <memory.h>
 4 #include <algorithm>
 5 using namespace std;
 6 //188ms
 7 const int maxnum=15001;
 8 struct node
 9 {
10     int digit;
11     int number;
12 }array[maxnum];
13 int tree[maxnum];
14 int res[maxnum];
15 int n;
16 
17 void update(int index,int add)
18 {
19     while(index<=n)
20     {
21         tree[index]+=add;
22         index+=(-index)&index;
23     }
24 }
25 
26 int getsum(int index)  //原序列中index位置之前小于等于array[index]的个数
27 {
28     int sum=0;
29     while(index>0)
30     {
31         sum+=tree[index];
32         index-=(-index)&index;
33     }
34     return sum;
35 }
36 
37 bool cmp(struct node a,struct node b)
38 {
39     if(a.digit==b.digit)  //因为我离散化了,然后坐标里有重复的数字,因此需要在这里保存稳定性
40         return a.number<b.number;
41     return a.digit<b.digit;
42 }
43 
44 int main()
45 {
46     scanf("%d",&n);
47     int i,temp;
48     for(i=1;i<=n;i++)
49     {
50         scanf("%d%d",&array[i].digit,&temp);
51         array[i].number=i;
52     }
53     sort(array+1,array+1+n,cmp);
54     memset(tree,0,sizeof(tree));
55     memset(res,0,sizeof(res));
56     for(i=1;i<=n;i++)
57     {
58         update(array[i].number,1);
59         res[getsum(array[i].number)-1]++; //这里要减一,不包括它本身
60     }
61     for(i=0;i<n;i++)
62         printf("%d\n",res[i]);
63     return 0;
64 }

 

转载于:https://www.cnblogs.com/pushing-my-way/archive/2012/08/17/2643761.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值