• 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," 
    "[i==n]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    高级程序员应该具备什么能力
    二 八 定 律
    二八定律全面分析
    Java 网络爬虫获取网页源代码原理及实现
    vijosP1371 方程的解
    vijosP1413 Valentine’s Present
    vijosP1289 老板娘的促销方案
    vijosP1092 全排列
    vijosP1049 送给圣诞夜的礼品
    vijosP1210 盒子与球
  • 原文地址:https://www.cnblogs.com/bin-gege/p/6895179.html
Copyright © 2020-2023  润新知