CodeForces - 1208D Restore Permutation 线段树

题目链接:https://cn.vjudge.net/problem/CodeForces-1208D

题解:从后往前操作,这样就能通过si确定出pi是什么,当然不能枚举,线段树维护下当前每个数如果放在当前位置的话si是多少,然后就是线段树的基本操作了,区间更新点查询

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
struct node {
	int l, r;
	ll val, laz;
}tree[N << 2];
int n;
ll a[N];
int pos[N];
void build(int l, int r, int cur) {
	tree[cur].l = l;
	tree[cur].r = r;
	tree[cur].laz = 0;
	if(l == r) {
		tree[cur].val = 1LL * (l - 1) * l / 2;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, cur << 1);
	build(mid + 1, r, cur << 1 | 1);
	tree[cur].val = max(tree[cur << 1].val , tree[cur << 1 | 1].val);
}
void pushdown(int cur) {
	if(tree[cur ].laz) {
		tree[cur << 1].laz += tree[cur].laz;
		tree[cur << 1 | 1].laz += tree[cur].laz;
		tree[cur << 1].val += tree[cur].laz;
		tree[cur << 1 | 1].val += tree[cur].laz;
		tree[cur].laz = 0;
	}
}
void update(int pl, int pr, int cur, ll val) {
	if(pl <= tree[cur].l && tree[cur].r <= pr) {
		tree[cur].val += val;
		tree[cur].laz += val;
		return;
	}
	pushdown(cur);
	if(pl <= tree[cur << 1].r) update(pl, pr, cur << 1, val);
	if(pr >= tree[cur << 1 | 1].l) update(pl, pr, cur << 1 | 1, val); 
	tree[cur].val = max(tree[cur << 1].val, tree[cur << 1 | 1].val);
}
int query(int cur, ll val) {
//	cout << tree[cur].l << " " << tree[cur].r << " " << tree[cur].val << endl;
 	if(tree[cur].l == tree[cur].r) return tree[cur].l;
	pushdown(cur);
	if(tree[cur << 1].val >= val) return query(cur << 1, val);
	else return query(cur << 1 | 1, val);
}
int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
	build(1, n, 1);
	for(int i = n; i >= 1; i--) {
		
		pos[i] = query(1, a[i]);
		if(pos[i] < n) update(pos[i] + 1, n, 1, -pos[i]);
		update(pos[i], pos[i], 1, -100000000000);
	}
	for(int i = 1; i <= n; i++)
		printf("%d%c", pos[i], " \n"[i == n]);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值