题目大意

对于二维平面上的n个点,给出点的坐标。定义一个点A覆盖的点的个数为满足以下条件的点B的个数:点B的x <= 点A的x坐标,点B的y坐标 <= 点A的y坐标。 
    给出N个点的坐标,求出覆盖点的个数分别为0, 1, ... N-1 的点各有多少个。

题目分析

对于二维平面的点问题,可以考虑先进行行列排序,然后进行处理。对点进行排序(y从小到大,y相同,x从小到大)之后,按照y从小到大进行:单独考虑一行的点的x坐标,此时x坐标是升序的,因此当前点的肯定可以覆盖当前行中的之前访问的点;对于下方的点,它们的y坐标肯定小于当前点的y坐标,因此只考虑点的x坐标,如果x坐标小于等于当前点的x坐标,则点被当前点覆盖。 
    于是问题就化为了,按照从左下到右上的顺序遍历每个点的时候,比较该点和之前访问过的点的x坐标,如果统计之前点中x坐标小于等于当前点x坐标的个数。也就相当于在x轴上从坐标0到坐标 point.x 这个区间内的点的个数,即一个区间统计问题。 
    区间统计问题,可以采用线段树来进行解决。具体做法是,线段树中的每个节点包含的区间为x坐标轴上的一个范围,遍历到一个点的时候,将点的x坐标插入到线段树中,线段树中的每个节点保存该节点所包含区间内被插入的点的个数。 
这样可以通过两种方式来更新计数: 
1. 从根向下插入点的时候,从根到叶子节点沿途经过的每个点的计数值w都加1 
2. 更新到叶子节点的时候,叶子节点的w值加1,然后通过pushup操作,更新到父节点

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<algorithm> #define MIN(a, b) a <b? a:b
#define MAX(a, b) a >b? a :b
#define MAX_NUM 32005
#define MAX_NODE 15005
struct Point{
int x;
int y;
};
Point gPoints[MAX_NODE];
int gCoverNum[MAX_NODE]; //覆盖i个点的点的数目用 gCoverNum[i]表示
struct TreeNode{
int beg;
int end;
int w; //表示该节点所代表区间中被插入的点的个数,初始为0,之后每次插入时候,从上往下依次增加
int Mid(){
return (beg + end) / 2;
}
TreeNode(){
beg = end = w = 0;
}
}; TreeNode gTreeNodes[MAX_NUM * 4]; //初始化建树,主要初始化节点的边界和w
void BuildTree(int node, int left, int right){
gTreeNodes[node].beg = left;
gTreeNodes[node].end = right;
gTreeNodes[node].w = 0;
if (left == right){
return;
}
int mid = (left + right) / 2;
BuildTree(2*node + 1, left, mid);
BuildTree(2*node + 2, mid + 1, right);
} void PushUp(int node){
gTreeNodes[node].w = (gTreeNodes[2 * node + 1].w + gTreeNodes[node * 2 + 2].w);
} //向以node为根的树中插入x,沿途中经过的节点的w值均加1
void Insert(int node, int x){
// gTreeNodes[node].w++;
if (gTreeNodes[node].beg == gTreeNodes[node].end){
//不在上面 gTreeNodes[node].w++;,则在这里执行,这样在最后执行 pushup操作。其效果和 开始的时候执行gTreeNodes[node].w++;一样
gTreeNodes[node].w++;
return;
}
int mid = gTreeNodes[node].Mid();
if (x > mid){
Insert(2 * node + 2, x);
}
else
Insert(2 * node + 1, x); //如果不使用上面的 gTreeNodes[node].w++;,则可以使用 PushUp操作,从下往上更新(由于递归的性质,会使得从叶节点到根都会被更新)
//也就相当于 从上往下插入的时候,每经过一个点都将 w 值加 1
PushUp(node);
} //在以node节点为根的树中查询区间 [s, e]中的元素数目
int Query(int node, int s, int e){
if (gTreeNodes[node].beg > e || gTreeNodes[node].end < s){
return 0;
}
if (gTreeNodes[node].beg >= s && gTreeNodes[node].end <= e){
return gTreeNodes[node].w;
}
int mid = gTreeNodes[node].Mid();
int sum = 0;
sum += Query(2 * node + 1, s, MIN(mid, e));
sum += Query(2 * node + 2, MAX(s, mid + 1), e);
return sum;
}
int main(){
int n;
scanf("%d", &n);
int max_end = 0;
for (int i = 0; i < n; i++){
scanf("%d%d", &gPoints[i].x, &gPoints[i].y);
max_end = MAX(max_end, gPoints[i].x);
gCoverNum[i] = 0;
}
BuildTree(0, 0, max_end);
for (int i = 0; i < n; i++){
int count = Query(0, 0, gPoints[i].x);
gCoverNum[count] ++;
Insert(0, gPoints[i].x);
}
for (int i = 0; i < n; i++){
printf("%d\n", gCoverNum[i]);
}
return 0;
}

poj_2352 线段树的更多相关文章

  1. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  2. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  3. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  4. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  5. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  6. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  7. CF719E(线段树+矩阵快速幂)

    题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作 分析:线段树 线段树的每个节点表示(f[i],f[i-1])这 ...

  8. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

  9. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

随机推荐

  1. MD5算法实现

    MD5算法的简要叙述为: MD5以512位分组来处理输入的信息(512位分组?每次处理都取出512位数据?), 每一分组又被划分为16个32位子分组(16乘32刚好是512), 经过一些列的处理后(怎 ...

  2. KafkaStream实现wordcount

    KTable应用 KTable wordCounts = textLines // Split each text line, by whitespace, into words. .flatMapV ...

  3. excel导出功能优化

    先说说优化前,怎么做EXCEL导出功能的: 1. 先定义一个VO类,类中的字段按照EXCEL的顺序定义,并且该类只能用于EXCEL导出使用,不能随便修改. 2. 将查询到的结果集循环写入到这个VO类中 ...

  4. iOS边练边学--UIPickerView和UIDatePicker的简单使用

    一.点菜系统练习(UIPickerView) <1>UIPickerView的常用代理方法介绍 #pragma mark - <UIPickerViewDelegate> // ...

  5. Entity Framework表拆分

    一.概念 表拆分:一个表拆分成多个实体,例如Photograph表,可以拆分为Photograph和PhotographFullImage两张表. Photograph实体结构: using Syst ...

  6. ruby send respond_to

    http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html http://galeki.is-progr ...

  7. java分布式集群

    http://blog.csdn.net/guzicheng/article/details/11580841

  8. Step download timeout (120 sec)

    Step download timeout (120 sec)  --------- Troubleshooting-----------------------------------    修改S ...

  9. 关于Cocos2d-x中物理世界的物体乱跳的问题的解决

    这是电脑短时间内帧率低,无法满足游戏配置的帧率引起的. 解决方法: 第一种: 1.打开AppDelegate.cpp文件 2.把director->setAnimationInterval(1. ...

  10. 获取platformVersion、deviceName、appPackage

    命令获取如下: 手机与电脑连接 devicename:    adb devices platformversion :   adb shell getprop ro.build.version.re ...