cf 1208D. Restore Permutation 线段树

D. Restore Permutation
 

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

There is a hidden permutation of length nn.

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

Your task is to restore the permutation.

Input

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

The second line contains nn integers s1,s2,,sns1,s2,…,sn (0sin(n1)20≤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,,pnp1,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 ii there is no index jj satisfying both conditions, hence sisi are always 00.

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

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

 

#include <bits/stdc++.h> 
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;  
const int N = 2e5+10;  
const int maxh = 4*N;  
typedef long long ll;
int ans[maxh];
struct node      
{      
    int l;      //左边界     
    int r;      // 右边界     
    ll val, lazy;    //节点所维护的区间[l, r]的权值, 懒惰标记      
}t[maxh];//N为总节点数      
ll val[N]; //原数组   
  
void pushup(int n)  
{  
    t[n].val =min (t[2*n].val, t[2*n+1].val);    
}  
void build(int n,int l,int r)  
{  
    t[n].l = l;     //记录维护的原数组的左端点   
    t[n].r = r;     //记录维护的右端点   
    t[n].lazy = 0;  //标记下懒惰数组   
    if(l==r){       //l==r,表示叶子节点,  
        t[n].val = val[l];    //因为l==r,那么这个节点维护的值就是原数组val[l]的值   
        return;  
    }         
    int mid = (l+r)>>1;  
    build(n*2,l,mid);      //递归建左子树   
    build(n*2+1,mid+1,r);  //递归建左子树  
    pushup(n);             //求该点的权值   
}  
void updateOne(int n,int idx,ll C)  
{  
    int l = t[n].l;//左端点   
    int r = t[n].r;//右端点   
    if(l==r)    //l==r,到了叶子节点   
    {  
        t[n].val = C;    //更新权值   
        return;   
    }     
    int mid = (l+r)>>1;  
   if(idx<=mid)     //val[idx]由左节点维护   
        updateOne(n*2,idx,C);  
   else          //val[idx]由右节点维护   
        updateOne(n*2+1,idx,C);  
    pushup(n);    //向上更新   
}   
void pushdown(int n)  
{  
    int l = t[n].l;  
    int r = t[n].r;  
    if(l==r)//叶子节点没有子结点   
        return;  
    if(t[n].lazy)//懒惰标记不为0才能向下更新   
    {     
        //int mid = (l+r)/2;  
        t[2*n].val += t[n].lazy;//更新左节点权值   
        t[2*n+1].val += t[n].lazy;//更新右节点权值  
        t[2*n].lazy += t[n].lazy;         //更新左节点标记   
        t[2*n+1].lazy += t[n].lazy;       //更新右节点标记   
        t[n].lazy = 0;                    //清除标记      
    }  
}  
//int query(int n,int L,int R)  
//{  
//    int l = t[n].l;  
//    int r = t[n].r;  
//    if(L<=l && r<=R)    //被包括直接返回   
//        return t[n].val;  
//    pushdown(n);        //向下更新   
//    int ans = 0;        //保持答案   
//    int mid = (l+r)>>1;  
//    if(L<=mid)           //查询区间与左节点维护区间有交集   
//        ans += query(2*n,L,R);//加上左节点交集区间的答案   
//    if(R>mid)  
//        ans += query(2*n+1,L,R);//加上右节点交集区间的答案   
//    return ans;  
//}  
void updateRange(int n,int L,int R,int C)  
{  
    int l = t[n].l;  
    int r = t[n].r;  
    if(L<=l && r<=R)    //待更新区间为[L, R],而[l, r]是[L, R]的子集所以更新   
    {  
        t[n].val += C;    //更新权值   
        t[n].lazy += C;           //更新标记      
        return;  
    }  
    pushdown(n);    //向下更新   
    int mid = (l+r)>>1;  
    if(L<=mid)      //左节点维护的区间与[L, R]有交集   
        updateRange(2*n,L,R,C);  
    if(R>mid)      //右节点维护的区间与[L, R]有交集   
        updateRange(2*n+1,L,R,C);  
    pushup(n);     //向上更新   
}
int findd0(int idx) {
		int l=t[idx].l;
		int r=t[idx].r;
		if ( l== r) {
			return l;
		} else {
			pushdown(idx);
			int res = -1;
			if (t[2*idx +1 ].val == 0) {
				res = findd0(2*idx +1);
			} else {
				res = findd0(2 * idx);
			}
			pushup( idx );
			return res;
		}
}
int main()  
{ 
	ios_base::sync_with_stdio(false);
	cin.tie(0); 
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>val[i];
	}
	build(1,1,n);
//	for(int i=1;i<=n;i++){
//		cout<<"n:"<<i<<" l:"<<t[i].l<<" r:"<<t[i].r<<"val:"<<t[i].val<<endl;
//	}
	for(int i=1;i<=n;i++){
		int cnt=findd0(1);  
//		cout<<cnt<<" ";
		ans[cnt]=i;
		updateOne(1,cnt,inf);	

		if( cnt+1>n) 	continue;     
		updateRange(1,cnt+1,n,-i);	
		//cout<<t[15].l<<" "<<t[15].r<<" "<<t[15].val<<endl;
	}
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<" ";
	}
	cout<<endl;
    return 0;   
}  

  

posted @ 2019-09-13 16:02  杰瑞与汤姆  阅读(110)  评论(0)    收藏  举报