Restore Permutation(思维+线段树)

https://codeforces.com/contest/1208/problem/D

D. Restore Permutation

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

An array of integers p1,p2,…,pn is called a permutation if it contains each number from 1 to n exactly once. For example, the following arrays are permutations: [3,1,2],[1],[1,2,3,4,5]and [4,3,1,2]. The following arrays are not permutations: [2],[1,1],[2,3,4].

There is a hidden permutation of length n.

For each index i, you are given si, which equals to the sum of all pj such that j<i and pj<pi. In other words, sisi is the sum of elements before the i-th element that are smaller than the i-th element.

Your task is to restore the permutation.

Input

The first line contains a single integer nn (1≤n≤2⋅10^5) — the size of the permutation.

The second line contains nn integers s1,s2,…,sns1,s2,…,sn (0≤si≤n(n−1)/2).

It is guaranteed that the array ss corresponds to a valid permutation of length nn.

Output

Print nn integers p1,p2,…,pn— the elements of the restored permutation. We can show that the answer is always unique.

Examples

input

Copy

3
0 0 0

output

Copy

3 2 1

input

Copy

2
0 1

output

Copy

1 2

input

Copy

5
0 1 1 1 10

output

Copy

1 4 3 2 5

Note

In the first example for each i there is no index j satisfying both conditions, hence sisi are always 0.

In the second example for i=2 it happens that j=1 satisfies the conditions, so s2=p1.

In the third example for i=2,3,4 only j=1 satisfies the conditions, so s2=s3=s4=1. For i=5 all j=1,2,3,4 are possible, so s5=p1+p2+p3+p4=10.

题意:有一个序列p,给你一个序列s,s[i]的值为p[1]到p[i-1]中比p[i]小的数的和,让你求出p序列

分析:从后往前操作,这样就能通过si确定出pi是什么 

查找第一个和大于s[i]的位置就是p[i],返回的时候要把p[i]减去

#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define max(a,b) a>b?a:b
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll tr[N<<2];
ll s[N];
int pos[N];
void build(int l,int r,int p){
	if(l==r){
		tr[p]=l;
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,p<<1);
	build(mid+1,r,p<<1|1);
	tr[p]=tr[p<<1]+tr[p<<1|1];
} 
int query(int l,int r,int p,ll val){
	if(l==r){
		tr[p]=0;
		return l;
	}
	int mid=(l+r)>>1;
	int ans=0;
	if(tr[p<<1]>val){
		ans=query(l,mid,p<<1,val);
		tr[p]-=ans;
	}
	else{
		ans=query(mid+1,r,p<<1|1,val-tr[p<<1]);
		tr[p]-=ans; 
	}
	return ans;
}
int main(){
    int n;
    scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%I64d",&s[i]); 
	build(1,n,1);
    for(int i=n;i>=1;i--){
    	pos[i]=query(1,n,1,s[i]);
	}
	for(int i=1;i<=n;i++) printf("%d%c",pos[i]," \n"[i==n]); 
	return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值