HDU 5592 还原逆序数(树状数组+二分)

来源:互联网 发布:she候鸟 知乎 编辑:程序博客网 时间:2024/06/06 05:48

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

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxn=50000+100;int a[maxn],pre[maxn],c[maxn],b[maxn];int n;void add(int x,int d){while(x<=n) {c[x]+=d;x+=x&(-x);}}int sum(int x){int ans=0;while(x>0) {ans+=c[x];x-=x&(-x);}return ans;}int main(){int t,i,j,l,r,num;scanf("%d",&t);while(t--) {memset(c,0,sizeof(c));scanf("%d",&n);pre[0]=0;for(i=1;i<=n;i++) {scanf("%d",&pre[i]);a[i]=pre[i]-pre[i-1];add(i,1);}for(i=n;i>0;i--) {l=1;r=n;while(l<=r) {int mid=(l+r)>>1;num=sum(n)-sum(mid);if(num<=a[i]) r=mid-1;else l=mid+1;}b[i]=l;add(l,-1);}for(i=1;i<=n;i++) {printf("%d",b[i]);if(i!=n) printf(" ");}printf("\n");}return 0;}



0 0
原创粉丝点击