CodeForces 538F A Heap of Heaps 主席树

Andrew skipped lessons on the subject 'Algorithms and Data Structures' for the entire term. When he came to the final test, the teacher decided to give him a difficult task as a punishment.

The teacher gave Andrew an array of n numbers a1, ..., an. After that he asked Andrew for each k from 1 to n - 1 to build a k-ary heap on the array and count the number of elements for which the property of the minimum-rooted heap is violated, i.e. the value of an element is less than the value of its parent.

Andrew looked up on the Wikipedia that a k-ary heap is a rooted tree with vertices in elements of the array. If the elements of the array are indexed from 1 to n, then the children of element v are elements with indices k(v - 1) + 2, ..., kv + 1 (if some of these elements lie outside the borders of the array, the corresponding children are absent). In any k-ary heap every element except for the first one has exactly one parent; for the element 1 the parent is absent (this element is the root of the heap). Denote p(v) as the number of the parent of the element with the number v. Let's say that for a non-root element v the property of the heap is violated if av < ap(v).

Help Andrew cope with the task!

Input

The first line contains a single integer n (2 ≤ n ≤ 2·105).

The second line contains n space-separated integers a1, ..., an ( - 109 ≤ ai ≤ 109).

Output

in a single line print n - 1 integers, separate the consecutive numbers with a single space — the number of elements for which the property of the k-ary heap is violated, for k = 1, 2, ..., n - 1.

Examples

Input

5
1 5 4 3 2

Output

3 2 1 0

Input

6
2 2 2 2 2 2

Output

0 0 0 0 0

Note

Pictures with the heaps for the first sample are given below; elements for which the property of the heap is violated are marked with red.

   

In the second sample all elements are equal, so the property holds for all pairs.

 

 

题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么该节点称为违规点,统计出1~n-1完全叉树各自的违规点的个数。

思路:对于一个完全k叉树,假设父亲的编号为i,那么i点的第一个孩子编号为(i-1)*k+2,最后一个孩子的编号为min(i*k+1,n)。

对于每一个可行点,都查询他的孩子即区间[(i-1)*k+2,min(i*k+1,n)]中有多少个小于这个该点权值的数。

 

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
vector<int> v;
int n,cnt,ans,a[maxn],root[maxn];
struct node{
	int l;
	int r;
	int sum;
}tree[maxn*40];
int getid(int x)
{
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void build(int &cur,int l,int r)
{
	cur=++cnt;
	tree[cur].sum=0;
	if(l==r) return ;
	int m=(l+r)>>1;
	build(tree[cur].l,l,m);
	build(tree[cur].r,m+1,r);
}
void update(int l,int r,int &now,int last,int pos)
{
	now=++cnt;
	tree[now]=tree[last];
	tree[now].sum++;
	if(l==r) return ;
	int m=(l+r)>>1;
	if(pos<=m) update(l,m,tree[now].l,tree[last].l,pos);
	else update(m+1,r,tree[now].r,tree[last].r,pos);
}
int query(int x,int y,int L,int R,int l,int r)
{
	if(L<=l&&r<=R) return tree[y].sum-tree[x].sum;
	int m=(l+r)>>1;
	int res=0;
	if(L<=m) res+=query(tree[x].l,tree[y].l,L,R,l,m);
	if(R>m) res+=query(tree[x].r,tree[y].r,L,R,m+1,r);
	return res;
}
int main()
{
	scanf("%d",&n);
	cnt=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		v.push_back(a[i]);
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	build(root[0],1,n);
	for(int i=1;i<=n;i++) update(1,n,root[i],root[i-1],getid(a[i]));
	for(int k=1;k<=n-1;k++)
	{
		ans=0;
		for(int i=1;(i-1)*k+2<=n;i++)
		{
			int l=(i-1)*k+2,r=min(i*k+1,n);
			if(getid(a[i])-1) ans+=query(root[l-1],root[r],1,getid(a[i])-1,1,n);
		}
		if(k==n-1) printf("%d\n",ans);
		else printf("%d ",ans);
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值