poj_2182 线段树/树状数组
题目大意
n个数排成一排(不知道大小,只是占了一个位置),从a[1]到a[n]进行遍历,对于每个a[i],给出从a[1]到a[i-1]中小于a[i]数的个数。要求出 a[1]到a[n]中这n个数的相对顺序。
题目分析
对于每个数 a[i], 给出了从 a[1] -- a[i-1]中小于a[i]的个数 less[i].
从n到1逆序查看, less[n] 表示前n-1个数中小于a[n]的个数,则可以确定a[n]的位置为 less[n] + 1
类似的对于 i,为了确定a[i]在所有n个数中的序号,将这个任务分为两部分:
(1)在 a[1] -- a[i-1]中有多少个数小于a[i], 题目给出了为 less[i]
(2)在a[i+1]---a[n]中有多少个数小于 a[i], 设为t
则 a[i] 在所有n个数中的序号(按照从小到大排序)为 k = less[i] + t + 1
但是,t并不好直接求出,则观察k的性质。对于a[i]在所有n个数中的位置k,1---k-1中包括 less[i]个在 a[1] -- a[i-1]中的元素,同时包括t个在a[i+1]---a[n]中的元素,在a[i+1]---a[n]中的元素已经确定了他们在整个n个数中的位置(我们是从后往前进行计算的),则 1----k-1中就可以确定那t个元素的位置。
为了确定k的位置,则设置一个数组b[1]--b[n],初始全部为0,从n到1统计,若a[i]的位置确定下来为p,则 b[p] = 1.则对于任意的k,b[1]---b[k]中1的个数表示 1----k中被占用的位置,0 的位置表示未被占用的位置。
对于 a[i],找到某个k,使得其b[1]--b[k-1]中0的个数正好为 less[i]个,则k的位置就是 a[i]在整个n个数中的按照大小排序的位置
实现(c++)
1. 线段树
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h> #define MAX_COW_NUM 80010
#define MAX_NODE_NUM 4*MAX_COW_NUM int gLess[MAX_COW_NUM];
int gPos[MAX_COW_NUM];
struct Node{
int beg;
int end;
int sum_zero;
int Mid(){
return (beg + end) >> 1;
}
};
Node gNodes[MAX_NODE_NUM];
void BuildTree(int beg, int end, int index){
gNodes[index].beg = beg;
gNodes[index].end = end;
if (beg == end){
gNodes[index].sum_zero = 1;
return;
}
int left = 2 * index + 1;
int right = 2 * index + 2;
int mid = (beg + end) >> 1;
BuildTree(beg, mid, left);
BuildTree(mid + 1, end, right);
gNodes[index].sum_zero = gNodes[left].sum_zero + gNodes[right].sum_zero;
}
//对于每个数 a[i], 给出了从 a[1] -- a[i-1]中小于a[i]的个数 less[i].
//从n到1逆序查看, less[n] 表示前n-1个数中小于a[n]的个数,则可以确定a[n]的位置为 less[n] + 1
//类似的对于 i,为了确定a[i]在所有n个数中的序号,将这个任务分为两部分:
//(1)在 a[1] -- a[i-1]中有多少个数小于a[i], 题目给出了为 less[i]
//(2)在a[i+1]---a[n]中有多少个数小于 a[i], 设为t //则 a[i] 在所有n个数中的序号(按照从小到大排序)为 k = less[i] + t + 1 //t 并不好直接求出,则观察k的性质。对于a[i]在所有n个数中的位置k,1---k-1中包括 less[i]个在 a[1] -- a[i-1]中的元素,
//同时包括 t个在a[i+1]---a[n]中的元素,在a[i+1]---a[n]中的元素已经确定了他们在整个n个数中的位置(我们是从后往前进行计算的),
//则 1----k-1中就可以确定那t个元素的位置。 //为了确定k的位置,则设置一个数组 b[1]--b[n],初始全部为0,从n到1统计,若a[i]的位置确定下来为p,则 b[p] = 1.
//则对于任意的k,b[1]---b[k]中1的个数表示 1----k中被占用的位置,0 的位置表示未被占用的位置。 //对于 a[i],找到某个k,使得其b[1]--b[k-1]中0的个数正好为 less[i]个,则k的位置就是 a[i]在整个n个数中的按照大小排序的位置 //利用线段树,找到 b[1]---b[pos]中 0的个数为k个的pos的位置
void FindKth(int k, int index, int& pos){
if (gNodes[index].sum_zero < k){
return;
}
if (gNodes[index].beg == gNodes[index].end){
gNodes[index].sum_zero = 0;
pos = gNodes[index].beg;
return;
}
int left = 2 * index + 1, right = 2 * index + 2;
gNodes[index].sum_zero--;
if (gNodes[left].sum_zero >= k){
FindKth(k, left, pos);
}
else{
FindKth(k - gNodes[left].sum_zero, right, pos);
}
} int main(){
int n;
scanf("%d", &n);
BuildTree(0, n - 1, 0);
for (int i = 2; i <= n; i++){
scanf("%d", &gLess[i]);
}
int pos = 0;
gLess[1] = 0;
for (int i = n; i >= 1; i--){
FindKth(gLess[i] + 1, 0, pos);
gPos[i] = pos + 1;
}
for (int i = 1; i <= n; i++){
printf("%d\n", gPos[i]);
}
return 0;
}
2. 树状数组
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define MAX_COW_NUM 80010
int gLowBit[MAX_COW_NUM];
int gC[MAX_COW_NUM];
int gLess[MAX_COW_NUM];
int gPos[MAX_COW_NUM];
bool gUsed[MAX_COW_NUM];
void InitLowBit(int n){
for (int i = 1; i <= n; i++){
gLowBit[i] = i&(-i);
}
}
void InitSequence(int n){
for (int i = 1; i <= n; i++){
gC[i] = gLowBit[i];
}
} //树状数组的更新
void Update(int p, int n, int add){
while (p <= n){
gC[p] += add;
p += gLowBit[p];
}
} //树状数组的查询
int Query(int p){
int result = 0;
while (p > 0){
result += gC[p];
p -= gLowBit[p];
}
return result;
} //二分法,查找满足要求的 位置
int Search(int k, int n){
int beg = 1, end = n + 1;
while (beg < end){
int mid = (beg + end) >> 1;
int sum_zero = Query(mid);
if (sum_zero == k){
while (mid + 1 < end){ //用于判断该位置是否被占用
if (gUsed[mid + 1])
mid++;
else
break;
}
return mid + 1;
}
else if (sum_zero < k){
beg = mid + 1;
}
else{
end = mid;
}
}
return 1;
} int main(){
int n;
scanf("%d", &n);
gLess[1] = 0;
InitLowBit(n);
InitSequence(n);
memset(gUsed, false, sizeof(gUsed)); for (int i = 2; i <= n; i++){
scanf("%d", &gLess[i]);
}
for (int i = n; i >= 1; i--){
int pos = Search(gLess[i], n);
gPos[i] = pos;
gUsed[pos] = true;
Update(pos, n, -1);
}
for (int i = 1; i <= n; i++){
printf("%d\n", gPos[i]);
}
return 0;
}
poj_2182 线段树/树状数组的更多相关文章
- CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...
- [bzoj1901][zoj2112][Dynamic Rankings] (整体二分+树状数组 or 动态开点线段树 or 主席树)
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- HDU 1556 线段树或树状数组,插段求点
1.HDU 1556 Color the ball 区间更新,单点查询 2.题意:n个气球,每次给(a,b)区间的气球涂一次色,问最后每个气球各涂了几次. (1)树状数组 总结:树状数组是一个查 ...
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- 【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings
谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结 ...
- HDU 1394 Minimum Inversion Number(最小逆序数/暴力 线段树 树状数组 归并排序)
题目链接: 传送门 Minimum Inversion Number Time Limit: 1000MS Memory Limit: 32768 K Description The inve ...
- POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树
题目链接:http://poj.org/problem?id=2299 求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法. 归并排序: #incl ...
- Turing Tree_线段树&树状数组
Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems abou ...
- HDU 1166 敌兵布阵 (数状数组,或线段树)
题意:... 析:可以直接用数状数组进行模拟,也可以用线段树. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000&quo ...
随机推荐
- valgrind: failed to start tool 'memcheck' for platform 'amd64-linux
valgrind运行错误 问题描述 valgrind运行时,无法找到相关工具文件,具体报错如下 valgrind: failed to start tool 'memcheck' for platfo ...
- IP数据包格式
IP数据包格式 0 4 8 16 31 |4位版本 | 4位首部长度 | 8位服务类型 | 16位总长度(字节数)| |16位标识 | 3位标志 | 13位片偏移 | |8位生存时间| 8位协议 | ...
- drupal7请求异常,执行时间过长的解决方法
drupal7请求错误,执行时间过长的解决办法 根据你的系统或网络设置Drupal不能读取网页,造成功能缺失.可能是web服务器配置或PHP设置引起的,可用更新.获取更新源.使用OpenID登 录或使 ...
- WPF教程五:布局之Canvas面板
Canvas:画布面板 画布,用于完全控制每个元素的精确位置.他是布局控件中最为简单的一种,直接将元素放到指定位置,主要来布置图面.使用Canvas,必须指定一个子元素的位置(相对于画布),否则所有元 ...
- Springboot 之 Hibernate自动建表(Mysql)
Springboot 之 Hibernate自动建表(Mysql) 2016年10月21日 10:39:44 阅读数:8180 本文章来自[知识林] 引入Maven依赖包 <dependency ...
- windows用命令行查看硬件信息
如何在windows系统自带命令查看硬件信息,怎样dos命令查看硬盘和内存/CPU信息?最直接的是:开始→运行→CMD打开命令提示符,在该窗口下输入systeminfo执行,即可看到几乎所有想知道的系 ...
- SparkR:数据科学家的新利器
摘要:R是数据科学家中最流行的编程语言和环境之一,在Spark中加入对R的支持是社区中较受关注的话题.作为增强Spark对数据科学家群体吸引力的最新举措,最近发布的Spark 1.4版本在现有的Sca ...
- jQuery 工具大搜集
jQuery 是一个非常棒的类库,但是为了保证代码的干净以及代码的精简,它只提供最核心的功能.所以就有了很多其他的工具来丰富jQuery的功能.我在使用这些工具的时候发现我常常重复的编写一些代码,所以 ...
- Servlet程序的入口点是?( )
Servlet程序的入口点是?( ) A.init() B.main() C.service() D.doGet() 解答:C
- Javascript汉字拼音互转
var PinYin = { charDict : "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJGYZZJJFKCCLZDHWDWZJLJPFYYN ...