题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5592
题意:
http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=654&pid=1003
题解:
对给的n个数做差分,即a[i]=a[i]-a[i-1],然后对做完差分之后的数组从后往前扫一遍(最后一个数就是代表整个序列中比它大的数有a[n-1]个,即,它是第a[n-1]+1大的数),每次求还未求出的数中的第(a[i]+1)大(第1大就是最大的意思)。
代码:
线段树:
#include<iostream>
#include<cstdio>
#include<cstring>
#define lson (o<<1)
#define rson ((o<<1)|1)
#define M (l+(r-l)/2)
using namespace std; const int maxn=+; int n,arr[maxn],ans[maxn]; int sumv[maxn<<]; void build(int o,int l,int r){
if(l==r){
sumv[o]=;
}else{
build(lson,l,M);
build(rson,M+,r);
sumv[o]=sumv[lson]+sumv[rson];
}
} int _ret;
void query(int o,int l,int r,int k){
if(l==r){
_ret=l;
sumv[o]=;
}else{
if(sumv[rson]>=k) query(rson,M+,r,k);
else query(lson,l,M,k-sumv[rson]);
sumv[o]=sumv[lson]+sumv[rson];
}
} int main(){
int tc;
scanf("%d",&tc);
while(tc--){
scanf("%d",&n);
build(,,n);
for(int i=;i<n;i++) scanf("%d",arr+i);
for(int i=n-;i>;i--) arr[i]-=arr[i-];
for(int i=n-;i>=;i--){
query(,,n,arr[i]+);
ans[i]=_ret;
}
for(int i=;i<n-;i++) printf("%d ",ans[i]);
printf("%d\n",ans[n-]);
}
return ;
}
二分+树状数组:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M (low+(hig-low)/2)
using namespace std; const int maxn=+; int n,arr[maxn],ans[maxn]; int sumv[maxn]; void add(int p,int x){
while(p<=n){
sumv[p]+=x;
p+=p&(-p);
}
} int sum(int p){
int ret=;
while(p>){
ret+=sumv[p];
p-=p&(-p);
}
return ret;
}
//lower_bound
int solve(int k){
int low=,hig=n;
while(low+<hig){
if(sum(M)<k) low=M;
else hig=M;
}
add(hig,-);
return hig;
} void init(){
memset(sumv,,sizeof(sumv));
} int main(){
int tc;
scanf("%d",&tc);
while(tc--){
scanf("%d",&n);
init();
for(int i=;i<=n;i++) add(i,);
for(int i=;i<n;i++) scanf("%d",arr+i);
for(int i=n-;i>;i--) arr[i]-=arr[i-];
for(int i=n-;i>=;i--){
ans[i]=solve(i+-arr[i]);
}
for(int i=;i<n-;i++) printf("%d ",ans[i]);
printf("%d\n",ans[n-]);
}
return ;
}