博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu 5592 BestCoder Round #65(树状数组)
阅读量:6834 次
发布时间:2019-06-26

本文共 1659 字,大约阅读时间需要 5 分钟。

题意:

 

ZYB有一个排列PP,但他只记得PP中每个前缀区间的逆序对数,现在他要求你还原这个排列.(i,j)(i < j)(i,j)(i
A_jAi>Aj
输入描述
第一行一个整数TT表示数据组数。接下来每组数据:第一行一个正整数NN,描述排列的长度.第二行NN个正整数A_iAi,描述前缀区间[1,i][1,i]的逆序对数.数据保证合法.1 \leq T \leq 51≤T≤5,1 \leq N \leq 500001≤N≤50000
输出描述
TT行每行NN个整数表示答案的排列.
输入样例
130 1 2
输出样例
3 1 2

 

 

思路:

a[i]表示[1,i]的逆序对,所以a[i] - a[i-1]便是i前面比第i个数大的,所以a[i]-a[i-1]+1便是第i个数在[1,i]中第几大。

所以用树桩数组全部初始化为1,然后二分+树状数组找出第k大的数然后把其赋值为0即可。

#include 
#include
#include
using namespace std;typedef long long ll;#define N 100050int a[N];int ans[N];int tree[N],dis[N];int n;void add(int x,int dx){ while(x <= n) { tree[x] += dx; x += x&(-x); }}int query(int x){ int sum = 0; while(x) { sum += tree[x]; x -= x&(-x); } return sum;}int main(){ int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i = 1; i <= n; i++) add(i,1); for(int i = 1; i <= n; i++) scanf("%d",a+i); for(int i = n; i >= 1; i--) { dis[i] = a[i]-a[i-1]+1; int l = 1,r = n; int tt; while(l < r) { int mid = (l+r)/2; if(query(mid) < dis[i]) l = mid+1; else if(query(mid) > dis[i]) r = mid-1; else { tt = r; r -= 1; } } ans[i] = r; add(l,-1); } for(int i= 1; i <= n; i++) printf("%d%c",n+1-ans[i],(i==n)? '\n':' '); }}

  

转载于:https://www.cnblogs.com/Przz/p/5409668.html

你可能感兴趣的文章
创建currvar、nextvar函数
查看>>
js设置全局变量 ajax中赋值
查看>>
1147: 查找子数组
查看>>
PLSQL_海量数据处理系列2_分区
查看>>
Linux 典型应用之Mysql
查看>>
架构设计之策略模式
查看>>
理解距(数学)
查看>>
web 开发之js---js 实现网页中播放wav的一种方法(flash播放器)
查看>>
openwrt下部署adbyby去广告大师 免luci 带自启动,自动开启透明代理
查看>>
[.Net 多线程处理系列专题七——对多线程的补充
查看>>
shell code one
查看>>
适配手机端浏览器
查看>>
面向对象
查看>>
[LeetCode] 526. Beautiful Arrangement
查看>>
获取本机IP,用户代理
查看>>
apple watch 与 iphone 之间的通信方式
查看>>
Ubantu 查看系统资源占用
查看>>
Oracle EBS在编码方式为AL32UTF8时的注意事项
查看>>
linux那些事
查看>>
通信服务器的架构问题
查看>>