题意:设原数组为a[i],pos[i]代表第 i 个位置之前有多少个数比a[i]大,求原数组a[i]。

这个题意是看了别人的题解才明白,我自己没读出来……

方法:假设我们从左往右放,因为后面的数还有可能影响前面的数的位置,所以在最后一个数放完之前,我们没法确定每个数的位置,所以我们反过来考虑,从右往左放。因为每个数前面比它大的数的个数pos[i]已知,我们可以不必关心这些数的具体数值,从而转化为它从右往左走了多少个空格,即pos[i]个,因此这个数放在第 pos[i] + 1 个空格位置上。这个空格所在位置的下标id,即是a[i]。a[i] = id;

树状数组或线段树记录区间[1, i ]的空格个数,对于放好的数,相应区间的空格数减1。

树状数组代码:5360 ms

#include <cstdio>
#include <cstring>
#include <cstdlib> const int MAXN = ; int pos[MAXN];
int C[MAXN];
int ans[MAXN];
bool vis[MAXN];
int N; int lowbit( int x )
{
return x&(-x);
} void Add( int x, int val )
{
while ( x <= N )
{
C[x] += val;
x += lowbit(x);
}
return;
} int Query( int x )
{
int res = ;
while ( x > )
{
res += C[x];
x -= lowbit(x);
}
return res;
} //注意二分查找的写法,不然很容易死循环
void BiSearch( int l, int r, int val, int &addr )
{
int mid;
while ( l <= r )
{
mid = ( l + r ) >> ;
int sum = Query( N ) - Query( mid - );
//printf( "mid=%d sum=%d\n", mid, sum );
if ( sum > val ) l = mid + ;
else
{
if ( sum == val )
{
if ( !vis[mid] ) //需要特殊判断一下这个点之前是否已经放好了
{
addr = mid;
r = mid - ;
}
else
{
l = mid + ;
}
}
else r = mid - ;
}
}
return;
} int main()
{
int T;
scanf( "%d", &T );
while ( T-- )
{
scanf( "%d", &N );
memset( C, , sizeof(int)*( N + ) );
memset( vis, false, sizeof(bool)*( N + ) );
for ( int i = ; i <= N; ++i )
{
scanf( "%d", &pos[i] );
Add( i, );
} for ( int i = N; i > ; --i )
{
int id;
BiSearch( , N, pos[i] + , id );
ans[i] = id;
vis[id] = true;
//printf( "id = %d\n", id );
Add( id, - );
}
printf( "%d", ans[] );
for ( int i = ; i <= N; ++i )
printf( " %d", ans[i] );
puts("");
}
return ;
}

线段树代码:1840 ms

#include <cstdio>
#include <cstring>
#include <cstdlib> #define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1 const int MAXN = ; int pos[MAXN];
int sum[MAXN << ];
int ans[MAXN];
int N, id; void build( int l, int r, int rt )
{
sum[rt] = r - l + ;
if ( l == r ) return; int m = ( l + r ) >> ;
build( lson );
build( rson );
return;
} void Update( int po, int l, int r, int rt )
{
--sum[rt];
if ( l == r )
{
id = l;
return;
} int m = ( l + r ) >> ; if ( po <= sum[rt << ] ) Update( po, lson );
else Update( po - sum[rt << ], rson ); return;
} int main()
{
int T;
scanf( "%d", &T );
while ( T-- )
{
scanf( "%d", &N );
build( , N, );
for ( int i = ; i <= N; ++i )
scanf( "%d", &pos[i] ); for ( int i = N; i > ; --i )
{
Update( pos[i] + , , N, );
ans[i] = N - id + ;
}
printf( "%d", ans[] );
for ( int i = ; i <= N; ++i )
printf( " %d", ans[i] );
puts("");
}
return ;
}

SPOJ 227 Ordering the Soldiers 线段树 / 树状数组的更多相关文章

  1. SPOJ 227 Ordering the Soldiers

    As you are probably well aware, in Byteland it is always the military officer's main worry to order ...

  2. HDOJ 4417 - Super Mario 线段树or树状数组离线处理..

    题意: 同上 题解: 抓着这题作死的搞~~是因为今天练习赛的一道题.SPOJ KQUERY.直到我用最后一种树状数组通过了HDOJ这题后..交SPOJ的才没超时..看排名...时间能排到11名了..有 ...

  3. CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)

    The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...

  4. 树状数组求第K小值 (spoj227 Ordering the Soldiers &amp;&amp; hdu2852 KiKi&#39;s K-Number)

    题目:http://www.spoj.com/problems/ORDERS/ and pid=2852">http://acm.hdu.edu.cn/showproblem.php? ...

  5. 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)

    54  种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...

  6. SPOJ DQUERY树状数组离线or主席树

    D-query Time Limit: 227MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Submit Status ...

  7. 小结:线段树 & 主席树 & 树状数组

    概要: 就是用来维护区间信息,然后各种秀智商游戏. 技巧及注意: 一定要注意标记的下放的顺序及影响!考虑是否有叠加或相互影响的可能! 和平衡树相同,在操作每一个节点时,必须保证祖先的tag已经完全下放 ...

  8. SPOJ 3267 D-query(离散化+在线主席树 | 离线树状数组)

    DQUERY - D-query #sorting #tree English Vietnamese Given a sequence of n numbers a1, a2, ..., an and ...

  9. [bzoj1901][zoj2112][Dynamic Rankings] (整体二分+树状数组 or 动态开点线段树 or 主席树)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

随机推荐

  1. 动态生成C# Lambda表达式

    转载:http://www.educity.cn/develop/1407905.html,并整理! 对于C# Lambda的理解我们在之前的文章中已经讲述过了,那么作为Delegate的进化使用,为 ...

  2. 学习JQuery的$.Ready()与OnLoad事件比较

    $(document).Ready()方法 VS OnLoad事件 VS $(window).load()方法接触JQuery一般最先学到的是何时启动事件.在曾经很长一段时间里,在页面载入后引发的事件 ...

  3. 前端之JavaScript第一天学习(1)-JavaScript 简介

    javaScript 是世界上最流行的编程语言. 这门语言可用于 HTML 和 web,更可广泛用于服务器.PC.笔记本电脑.平板电脑和智能手机等设备. JavaScript 是脚本语言 JavaSc ...

  4. JS 学习笔记--12---面向对象

    练习中使用的浏览器为IE10,如果各位朋友有不同意见或者本文有什么错误地方,望指正 ECMASCript有两种开发模式:函数式(面向过程)和面向对象.面向对象有一个很明显的标志,那就是类,我们可以通过 ...

  5. 设计模式之建造者模式(Builder)

    建造者模式原理:建造模式主要是用于产生对象的各个组成部分,而抽象工厂模式则用于产生一系列对象,建造者模式而且要求这些对象的组成部分有序. 代码如下: #include <iostream> ...

  6. json_encode charset

    json_encode  utf-8   mysql   charset  utf8

  7. linux yum 命令 详解

    linux yum命令详解 yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能 ...

  8. JavaScript 性能分析新工具 OneProfile

    OneProfile 是一个网页版的小工具,可以用全新的方式展示 JavaScript 性能分析的结果,帮助开发者洞悉函数调用关系,优化应用性能. 点击打开 OneProfile 背景 Chrome ...

  9. iOS打电话,发短信,发邮件,打开网址

    //调用自带mail [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://admin@hzl ...

  10. React.js 样式组件:React Style

    点这里 React Style 是 React.js 可维护的样式组件.使用 React Native StyleSheet.create一样的样式. 完全使用 JavaScript 定义样式: ? ...