Codeforces Round #406 (Div. 2) E. Till I Collapse(主席树)

题目链接:Codeforces Round #406 (Div. 2) E. Till I Collapse

题意:

给你n个数,对于每一个k(1<=k<=n),划分区间,每个区间只能有k个不同的数字,

问最小的划分区间的个数。

题解:

用主席树倒着将数插入,对于每个区间询问第k个不同数的位置就行了。

#include<bits/stdc++.h>
#define F(i,a,b) for(int i=a;i<=b;i++)
#define ___ freopen("in.txt","r",stdin);
using namespace std;
typedef long long ll;

const int N=1e5+7;

int root[N],a[N],cnt,pre[N],n;

struct node{int l,r,sum;}T[N*40];

void update(int l,int r,int &x,int y,int pos,int val)
{
    T[++cnt]=T[y],T[x=cnt].sum+=val;
    if(l==r)return;
    int mid=l+r>>1;
    if(mid>=pos)update(l,mid,T[x].l,T[y].l,pos,val);
    else update(mid+1,r,T[x].r,T[y].r,pos,val);
}

int query(int l,int r,int x,int k)
{
    if(l==r)return l;
    int mid=l+r>>1;
    if(k<=T[T[x].l].sum)return query(l,mid,T[x].l,k);
    else return query(mid+1,r,T[x].r,k-T[T[x].l].sum);
}

int main()
{
    scanf("%d",&n);
    F(i,1,n)scanf("%d",a+i);
    for(int i=n;i>0;i--)
    {
        update(1,n,root[i],root[i+1],i,1);
        if(pre[a[i]])update(1,n,root[i],root[i],pre[a[i]],-1);
        pre[a[i]]=i;
    }
    F(i,1,n)
    {
        int now=1,ans=0;
        while(now<=n)
        {
            if(T[root[now]].sum>i)now=query(1,n,root[now],i+1);
            else now=n+1;
            ans++;
        }
        printf("%d%c",ans," \n"[i==n]);
    }
    return 0;
}
View Code

 

posted @ 2017-05-23 17:37  bin_gege  阅读(270)  评论(0编辑  收藏  举报