Codeforces 538 F. A Heap of Heaps

[$>Codeforces \space 538 F. A Heap of Heaps<$](http://codeforces.com/contest/538/problem/F)

题目大意 :给出 \(n\) 个点,编号为 \(1 - n\) ,每个点有点权,将这些点构建成 \(k\) 叉树的形式 \((k \in [1, n - 1])\)
对于编号为 \(i\) 的点,它的儿子区间是 \([\ k(i-1)+2, \ \min(ki + 1, n)\ ]\) 如果说一个点违反堆性质,当且仅当它的点权小于它父亲的点权,对于所有 \((k \in [1, n - 1])\) 叉树,求出按照给定规则构建后违反堆性质的点的数量

\(1≤ n ≤ 2 \times 10^5\) , \(-10^9 \leq a_i \leq 10^9\)

解题思路 :

观察发现,按照题目规则构建的 \(k\) 叉树,有儿子的点最多只有 \(\frac{n}{k}\)

不妨暴力枚举 \(k\) ,对于每一个 \(k\) 枚举树中有儿子的点,统计其对应的儿子区间里权值比他小的点的数量

考虑本质上是一个二维数点,那么离散化 \(+\) 主席树就可以在 \(O(logn)\) 的时间内完成单次查询

考虑枚举部分的复杂度是一个类似于 \(\frac{n}{1} + \frac{n}{2} +..+ \frac{n}{n-1}\) 的调和级数状物,复杂度是 \(O(nlogn)\)

所以算法的总复杂度是 \(O(nlog^2n)\)


/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
#define N (1000005)
int s[N], a[N], rt[N], n;
struct SegmentTree{
	int rc[N*25], lc[N*25], sz[N*25], cnt;
	inline void ins(int &u, int pr, int l, int r, int pos){
		u = ++cnt, sz[u] = sz[pr] + 1;
		lc[u] = lc[pr], rc[u] = rc[pr];
		if(l == r) return; int mid = l + r >> 1;
		if(pos <= mid) ins(lc[u], lc[pr], l, mid, pos);
		else ins(rc[u], rc[pr], mid + 1, r, pos);
	}
	inline int query(int x, int y, int l, int r, int L, int R){
		if(l >= L && r <= R) return sz[y] - sz[x];
		int mid = l + r >> 1, res = 0;
		if(L <= mid) res += query(lc[x], lc[y], l, mid, L, R);
		if(mid < R) res += query(rc[x], rc[y], mid + 1, r, L, R);
		return res; 	
	}
}van;
inline int solve(int k){
	int ans = 0;
	for(int i = 1; i <= n; i++){
		int l = k * (i - 1) + 2, r = Min(n, k * i + 1);
		if(l > n) return ans;
		if(a[i] == 1) continue;
		ans += van.query(rt[l-1], rt[r], 1, n, 1, a[i] - 1);
	}	 
	return ans;
}
int main(){
	read(n);
	for(int i = 1; i <= n; i++) 
		read(a[i]), s[i] = a[i];
	sort(s + 1, s + n + 1);
	int sz = unique(s + 1, s + n + 1) - s - 1;
	for(int i = 1; i <= n; i++){
		a[i] = lower_bound(s + 1, s + sz + 1, a[i]) - s;
		van.ins(rt[i], rt[i-1], 1, n, a[i]);
	}
	for(int k = 1; k < n; k++) printf("%d ", solve(k));
	return 0;
}
posted @ 2018-07-13 07:52  Joyemang33  阅读(187)  评论(0编辑  收藏  举报