CSU 2222 权值树状数组

http://acm.csu.edu.cn:20080/csuoj/problemset/problem?pid=2222

Description

Wells有一个长度为N的数列Ai,这N个数互不相同

Wells已经计算完成了每个数对逆序对数量的贡献,也就是位置处于这个数之前但比这个数大的数的个数

现在Wells想请你通过这些信息复原原数列

Input

第一行包含一个正整数N(N<=100000)

第二行,N个正整数,为数列A中出现的数

第三行,N个整数,为前一行中对应的那个数对逆序对的贡献(Ai<=100000)

Output

一行,为复原后的数列

Sample Input

5
33 11 22 44 55
0 2 1 1 0

Sample Output

33 22 11 55 44

Hint

样例输出中11前33>11,22>11,所以11对逆序对的贡献为2

Source

题目大意:自己想了一个小时饶了无数弯路之后终于找到了正解。这题其实可以转化成求动态第k大的问题,我们来分析一波:先读入数列的值和对应的贡献,然后按照值从小到大排序,从小到大遍历该序列,因为第i个数的贡献为gxi,即i之前有gxi个数大于它,因此我们把它放到第gxi+1大的位置上即可。我们以样例为例:(11,2)、(22,1)、(33,0)、(44,1)、(55,0);此时可供选择的位置有:1、2、3、4、5;(1)因为11之前有2个大于它的元素而11又是当前最小的,因此要把11放到a[2+1]=a[3]=3的位置上,此时可供选择的位置有:1、2、4、5;(2)分析同上,要把22放到a[1+1]=a[2]=2的位置上,此时可供选择的位置有:1、4、5;(3)要把33放到a[0+1]=a[1]=1的位置上,此时可供选择的位置有:4、5;(4)要把44放到a[1+1]=a[2]=5的位置上,此时可供选择的位置有:4;(5)要把55放到a[0+1]=a[1]=4的位置上。现在清楚了吧~那么如何求动态第k大呢?就要用到权值树状数组了!还不知道这是什么玩意的同学请戳这里,初始我们对[1,n]的每一个i做add(i,1)操作,(add(i,1)即在树状数组中插入1个值为i的数)就得到了我们上面用到的位置序列,然后对于每个gxi,我们找到当前第gxi+1大的数,把vi放到该位置上同时把这个数从树状数组中删去即可。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;

struct node
{
	int v,gx;
	bool operator <(const node& x)const
	{
		return v<x.v;
	}
};

node a[100005];
int tree[100005];
int ans[100005];
int n;

inline int lowbit(int x)
{
	return x&(-x);
}

void add(int i,int v)
{
	for(;i<=n;i+=lowbit(i))
		tree[i]+=v;
}

int findk_th(int k)
{
	int re=0,sum=0;
	for(int i=20;i>=0;i--)
	{
		re+=(1<<i);
		if(re>=n||sum+tree[re]>=k)
			re-=(1<<i);
		else
			sum+=tree[re];
	}
	return re+1;
}

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i].v);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i].gx);
	sort(a,a+n);
	for(int i=1;i<=n;i++)
		add(i,1);
	int temp;
	for(int i=0;i<n;i++)
	{
		temp=findk_th(a[i].gx+1);
		ans[temp]=a[i].v;
		add(temp,-1);
	}
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	putchar('\n');
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值