题目大意:

给定一个长度为\(n\)的序列,要求将其划分为最少的若干段使得每段中不同的数字的种数不超过\(k\).

对于 \(k = 1 .. n\)输出所有的答案.

\(n \leq 10^5\)

题解:

考虑最坏情况下会分成多少段.

最坏分成\(\frac{n}{k}\)段。

所以对于每种\(k\)将其段数加起来。

有\(O(\sum_{k=1}^n\frac{n}{k})= O(n\log n)\)

所以我们可以考虑每次找出下一个端点进行转移。

复杂度为\(O(\text{转移}nlogn)\)

对于每次转移我们要找到最大的一个元素使得从当前点向右经过的不同的数字种数\(\leq k\)

假设说我们有一个数组\(f_{p,i}\)表示从\(p\)开始往后\(i\)是否是第一次出现。

那么我们就可以通过在线段树上二分的方式在\(\log n\)的时间确定这个坐标。

考虑对每一个\(p\)建立\(f_{p,i}\)的线段树。

然后发现\(f_p\)与\(f_{p+1}\)只有两个元素不同的区别。

所以可以建立可持久化线段树完成这个东西的维护。

复杂度\(O(n\log^2n)\)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 100010;
struct Node{
Node *ch[2];
int num;
void update(){
num = ch[0]->num + ch[1]->num;
}
}mem[maxn*40],*null,*it,*root[maxn];
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null;
null->num = 0;root[0] = null;
}
Node* modify(Node *rt,int l,int r,int pos,int val){
Node *p = it++;*p = *rt;
if(l == r){
p->num = val;
return p;
}
int mid = l+r >> 1;
if(pos <= mid) p->ch[0] = modify(p->ch[0],l,mid,pos,val);
else p->ch[1] = modify(p->ch[1],mid+1,r,pos,val);
p->update();return p;
}
inline int find(Node *p,int l,int r){
if(l == r && p->num != 0) return -1;
if(l == r) return l;
int mid = l+r >> 1;
if(p->ch[0]->num == 0) return max(mid,find(p->ch[1],mid+1,r));
else return find(p->ch[0],l,mid);
}
int query(Node *p,int l,int r,int k){
if(l == r) return l;
int mid = l+r >> 1;
if(k > p->ch[0]->num){
k -= p->ch[0]->num;
return query(p->ch[1],mid+1,r,k);
}else if(k < p->ch[0]->num) return query(p->ch[0],l,mid,k);
else return max(mid,find(p->ch[1],mid+1,r));
}
int nx[maxn],la[maxn],ws[maxn];
int a[maxn],n;
inline int solve(int k){
int pos = 1,x,ans = 0;
while(pos <= n){
x = query(root[pos],1,n,min(k,n-pos+1));
pos = x+1;++ ans;
}return ans;
}
int main(){
read(n);
rep(i,1,n) read(a[i]);
memset(ws,-1,sizeof ws);
rep(i,1,n){
la[i] = ws[a[i]];
ws[a[i]] = i;
}
memset(ws,-1,sizeof ws);
per(i,n,1){
nx[i] = ws[a[i]];
ws[a[i]] = i;
}
init();
root[1] = root[0];
rep(i,1,n){
if(la[i] == -1) root[1] = modify(root[1],1,n,i,1);
}
rep(i,2,n){
root[i] = modify(root[i-1],1,n,i-1,0);
if(nx[i-1] != -1) root[i] = modify(root[i],1,n,nx[i-1],1);
}
rep(k,1,n){
printf("%d",solve(k));
if(k != n) putchar(' ');
else putchar('\n');
}
return 0;
}

Codeforces 786C. Till I Collapse 主席树的更多相关文章

  1. Codeforces 786C Till I Collapse(树状数组+扫描线+倍增)

    [题目链接] http://codeforces.com/contest/786/problem/C [题目大意] 给出一个数列,问对于不同的k,将区间划分为几个, 每个区间出现不同元素个数不超过k时 ...

  2. Codeforces 786C Till I Collapse

    题意: 给出一个长度为n的序列,每个数值在1-n之间且为整数,现在要把这个序列划分为若干段,使得每一段的颜色种数不超过k,求最少的区间数目.对于从1到n的n种k的取值,分别输出这时的最少区间数目. 分 ...

  3. 【CodeForces】960 F. Pathwalks 主席树+动态规划

    [题目]F. Pathwalks [题意]给定n个点m条边的有向图,可能不连通有重边有自环.每条边有编号 i 和边权 wi ,求最长的路径(可以经过重复节点)满足编号和边权都严格递增.n,m,wi&l ...

  4. CodeForces - 597C:Subsequences (主席树+DP)

    For the given sequence with n different elements find the number of increasing subsequences with k + ...

  5. Codeforces 833B The Bakery(主席树 + 决策单调性优化DP)

    题目链接 The Bakery 题目大意:目标是把$n$个数分成$k$组,每个组的值为这个组内不同的数的个数,求$k$个组的值的和的最大值. 题目分析: 这道题我的解法可能和大众解法不太一样……我用主 ...

  6. Codeforces 813E Army Creation(主席树)

    题目链接  Educational Codeforces Round 22 Problem E 题意  给定一个序列,$q$次查询,询问从$l$到$r$中出现过的数字的出现次数和$k$取较小值后的和 ...

  7. Till I Collapse CodeForces - 786C (主席树区间加,二分最小值)

    大意: 给定序列, 将序列划分为若干段, 使得每段不同数字不超过k, 分别求出k=1...n时的答案. 考虑贪心, 对于某个k 从1开始, 每次查询最后一个颜色数<=k的点作为一个划分, 直到全 ...

  8. 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )

    在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...

  9. Codeforces Round #276 (Div. 1) E. Sign on Fence (二分答案 主席树 区间合并)

    链接:http://codeforces.com/contest/484/problem/E 题意: 给你n个数的,每个数代表高度: 再给出m个询问,每次询问[l,r]区间内连续w个数的最大的最小值: ...

随机推荐

  1. octotree神器 For Github and GitLab 火狐插件

    Code tree for GitHub and GitLabExtension to show code tree for GitHub and GitLab. Useful for develop ...

  2. oracle 定时删除3天前的备份数据

    不需要保留那么多,按公司要求只需要保留一个星期的即可. 1.那么有什么方法自动删除7天以前备份的*.log文件呢? 2.服务器过多,不可能一一手动创建,有没有自动完成这个创建计划任务的批处理呢? 首先 ...

  3. 关于Class.getResourceAsStream

    Properties properties = new Properties();    properties.load(new  InputStreamReader(CharactorTest.cl ...

  4. .babelrc参数小解

    .babelrc是用来设置转码规则和插件的,这种文件在window上无法直接创建,也无法在HBuilder中创建,甚至无法查看,但可以在sublime text中创建.查看并编辑. 当我们使用es6语 ...

  5. android 修改源码framework后如何编译【转】

    本文转载自:https://blog.csdn.net/fuchengbo000/article/details/43193801 1.如果在framework/base/core/res/res下添 ...

  6. 服务器windows 2003 安装SQL 2000+SP4

    (在windows 2003安装SQL 2000,对于03系统是没有32位和64位之分的) (32位系统需要重启机器,64不需要) 在站点下载数据库 解压后有两个文件夹 首先安装SQL2000 第1步 ...

  7. 开机启动顺序rc.local与chkconfig的不同

    /etc/rc.local文件有如下两行/etc/init.d/mysql start/etc/init.d/keepalived start /etc/rc.local是按脚本的顺序一个启动后启动下 ...

  8. 在shell中使用sendmail发送邮件

    cat > sendmymail.sh #!/bin/bash/usr/sbin/sendmail -t <<EOFFrom: Mail testing <abc@gmail. ...

  9. MSER最稳定极值区域源码分析

    最稳定极值区域介绍 如把灰度图看成高低起伏的地形图,其中灰度值看成海平面高度的话,MSER的作用就是在灰度图中找到符合条件的坑洼.条件为坑的最小高度,坑的大小,坑的倾斜程度,坑中如果已有小坑时大坑与小 ...

  10. Ubuntu18.04 升级python3后 安装pip3 后报错

    pip3 -VTraceback (most recent call last): File , in <module> from pip._internal import main Mo ...