您的位置:首页 > 其它

HDU 5592

2015-12-16 14:20 295 查看
原题:
http://acm.hdu.edu.cn/showproblem.php?pid=5592
线段树的变形,先说思路。

题目中给出了当前节点之前的逆序对数,则p[i]-p[i-1]就是对于p[i]来说,新增的逆序数,也就是比p[i]大的数,所以这时要考虑倒着处理,用线段树维护哪些数已经使用,哪些还未使用,p[i]-p[i-1]+1就是在还能用的序列中,第几大的数。我们用1表示数还没用,用0表示已经用了,这里就用到线段树的变形,每个节点维护着当前区间有几个1,我们的原则是先访问线段树的右节点,再左节点,因为右边的数大嘛。

需要注意的是,刚开始要将所有的叶子节点更新为1,再就是,当右节点不满足条件,要进入左节点时,一定用val减去右节点的值。

#include<stdio.h>
#include<string.h>
#define maxn 50005
int a[maxn],b[maxn],tree[maxn<<2];
int n,k;
void init(){
k = 1;
while(k<n)
k <<= 1;
memset(tree,0,sizeof(tree));
}
void upgrade(int index,int val){
index = index + k - 1;
tree[index] += val;
index /= 2;
while(index){
tree[index] = tree[index*2] + tree[index*2+1];
index /= 2;
}
}
int query(int index,int l,int r,int val){
if(l==r)
return l;
int m = (l+r)/2;
if(tree[index*2+1]>val)
query(index*2+1,m+1,r,val);
else
query(index*2,l,m,val-tree[index*2+1]);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
init();
for(int i = 1;i<=n;i++){
scanf("%d",&a[i]);
upgrade(i,1);
}
for(int i = n;i>0;i--){
int val = a[i] - a[i-1];
b[i] = query(1,1,k,val);
upgrade(b[i],-1);
}
for(int i = 1;i<n;i++)
printf("%d ",b[i]);
printf("%d\n",b
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: