码迷,mamicode.com
首页 > 其他好文 > 详细

[CF538F]A Heap of Heaps(主席树)

时间:2019-05-12 12:24:57      阅读:111      评论:0      收藏:0      [点我收藏+]

标签:sort   else   max   lse   数组   EAP   ==   枚举   scanf   

题面

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

分析

注意到完全k叉树的一个性质,v节点的儿子是k*(v-1)+2...kv+1,v节点的父亲为(v+k-2)/k

那我们可以暴力枚举k,然后枚举每个点i,但是我们没必要枚举叶子节点,也就是说i的范围是0到最后一个叶子节点n的父亲,即[0,(v+n-2)/k]

然后对于每个点i,在对应的子节点区间里查询值在[0,a[i]-1]里的节点个数。由于主席树维护的就是1~i中有多少个节点的值落在[l,r]内,直接区间求和然后相减就可以了

由于n个节点的k叉树最多有\(\frac{n}{k}\)个叶子节点

时间复杂度为\(\sum_{k=1}^{n-1} \frac{n}{k}=O(n\log n)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200005
#define maxlogn 20
using namespace std;
struct node{
#ifdef DEBUG
    int l;
    int r;
#endif
    int ls;
    int rs;
    int cnt; 
}tree[maxn*maxlogn];
int ptr;
inline void push_up(int x){
    tree[x].cnt=tree[tree[x].ls].cnt+tree[tree[x].rs].cnt;
}
void update(int &x,int last,int upos,int l,int r){
    x=++ptr;
    tree[x]=tree[last];
#ifdef DEBUG
    tree[x].l=l;
    tree[x].r=r;
#endif
    if(l==r){
        tree[x].cnt++;
        return;
    }
    int mid=(l+r)>>1;
    if(upos<=mid) update(tree[x].ls,tree[last].ls,upos,l,mid);
    else update(tree[x].rs,tree[last].rs,upos,mid+1,r);
    push_up(x);
}
int get_sum(int L,int R,int l,int r,int x){
    if(L<=l&&R>=r){
        return tree[x].cnt;
    }
    int mid=(l+r)>>1;
    int ans=0;
    if(L<=mid) ans+=get_sum(L,R,l,mid,tree[x].ls);
    if(R>mid) ans+=get_sum(L,R,mid+1,r,tree[x].rs);
    return ans;
}

int n;
int root[maxn];
int a[maxn];
int b[maxn];
int ans[maxn];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    int m=n;
    sort(b+1,b+1+m);
    m=unique(b+1,b+1+m)-b-1;
    for(int i=1;i<=n;i++){
        a[i]=lower_bound(b+1,b+1+m,a[i])-b;
    }
    for(int i=1;i<=n;i++){
        update(root[i],root[i-1],a[i],1,m);
    }
    
    for(int k=1;k<=n-1;k++){
        int lim=(n+k-2)/k;
        for(int i=1;i<=lim;i++){
            int l=k*(i-1)+2;
            int r=min(k*i+1,n);
            int cnt=0;
            if(a[i]-1<1) cnt=0; 
            else cnt=get_sum(1,a[i]-1,1,m,root[r])-get_sum(1,a[i]-1,1,m,root[l-1]);
            ans[k]+=cnt;
        }
    }
    for(int i=1;i<=n-1;i++){
        printf("%d ",ans[i]);
    }
}

[CF538F]A Heap of Heaps(主席树)

标签:sort   else   max   lse   数组   EAP   ==   枚举   scanf   

原文地址:https://www.cnblogs.com/birchtree/p/10851793.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!