cf 1208D. 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.
The first line contains a single integer nn (1≤n≤2⋅1051≤n≤2⋅105) — the size of the permutation.
The second line contains nn integers s1,s2,…,sns1,s2,…,sn (0≤si≤n(n−1)20≤si≤n(n−1)2).
It is guaranteed that the array ss corresponds to a valid permutation of length nn.
Print nn integers p1,p2,…,pnp1,p2,…,pn — the elements of the restored permutation. We can show that the answer is always unique.
3 0 0 0
3 2 1
2 0 1
1 2
5 0 1 1 1 10
1 4 3 2 5
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;
}

浙公网安备 33010602011771号