题目
展开
题目描述
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 nn numbers a_{1}a
1
, … , a_{n}a
n
. After that he asked Andrew for each kk from 1 to n-1n−1 to build a kk -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 kk -ary heap is a rooted tree with vertices in elements of the array. If the elements of the array are indexed from 1 to nn , then the children of element vv are elements with indices k(v-1)+2k(v−1)+2 , … , kv+1kv+1 (if some of these elements lie outside the borders of the array, the corresponding children are absent). In any kk -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)p(v) as the number of the parent of the element with the number vv . Let’s say that for a non-root element vv the property of the heap is violated if a_{v}<a_{p(v)} .
Help Andrew cope with the task!
输入格式
The first line contains a single integer nn ( 2<=n<=2·10^{5}2<=n<=2⋅10
5
).
The second line contains nn space-separated integers a_{1}a
1
, … , a_{n}a
n
( -10{9}<=a_{i}<=10{9}−10
9
<=a
i
<=10
9
).
输出格式
in a single line print n-1n−1 integers, separate the consecutive numbers with a single space — the number of elements for which the property of the kk -ary heap is violated, for k=1k=1 , 22 , … , n-1n−1 .
题意翻译
有一个小根堆,但是因为奇奇怪怪的原因,这个堆变成了一个k叉堆,而且不一定是合法的(即有若干个节点小于它的父亲)。问现在这个堆有多少不合法的元素。
输入输出样例
输入 #1复制
5
1 5 4 3 2
输出 #1复制
3 2 1 0
输入 #2复制
6
2 2 2 2 2 2
输出 #2复制
0 0 0 0 0
说明/提示
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.
思路
我们观察一个对于一棵 jj 叉树,求他的父亲的公式: (i + j - 2) /i。
这表示啥?这不就是表示对于许多的节点,他的父亲相同吗。
对于父亲相同的节点,我们把它分成一个块,然后直接用一个差分数组实现区间加,先判断是否不合法,不合法就用差分数组搞一搞,最后做一遍前缀和,输出答案即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N];
int ans[N];
int main()
{
n=readint();
for(int i=1; i<=n; i++) a[i]=readint();
for(int i=2; i<=n; i++)
{
int l=1;
while(l<=i-2)
{
int r=(i-2)/((i-2)/l);
if(a[(i-2)/l+1]>a[i])
{
ans[l]++;
ans[r+1]--;
}
l=r+1;
}
if(a[1]>a[i]) ans[l]++;
}
for(int i=2; i<n; i++) ans[i]+=ans[i-1];
for(int i=1; i<n; i++) printf("%d ",ans[i]);
printf("\n");
return 0;
}