Codeforces 538 F. A Heap of Heaps

\(>Codeforces \space 538 F. A Heap of Heaps<\)

题目大意 :给出 \(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;
}

猜你喜欢

转载自www.cnblogs.com/mangoyang/p/9303002.html