Codeforces 786C. Till I Collapse 主席树
题目大意:
给定一个长度为\(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 主席树的更多相关文章
- Codeforces 786C Till I Collapse(树状数组+扫描线+倍增)
[题目链接] http://codeforces.com/contest/786/problem/C [题目大意] 给出一个数列,问对于不同的k,将区间划分为几个, 每个区间出现不同元素个数不超过k时 ...
- Codeforces 786C Till I Collapse
题意: 给出一个长度为n的序列,每个数值在1-n之间且为整数,现在要把这个序列划分为若干段,使得每一段的颜色种数不超过k,求最少的区间数目.对于从1到n的n种k的取值,分别输出这时的最少区间数目. 分 ...
- 【CodeForces】960 F. Pathwalks 主席树+动态规划
[题目]F. Pathwalks [题意]给定n个点m条边的有向图,可能不连通有重边有自环.每条边有编号 i 和边权 wi ,求最长的路径(可以经过重复节点)满足编号和边权都严格递增.n,m,wi&l ...
- CodeForces - 597C:Subsequences (主席树+DP)
For the given sequence with n different elements find the number of increasing subsequences with k + ...
- Codeforces 833B The Bakery(主席树 + 决策单调性优化DP)
题目链接 The Bakery 题目大意:目标是把$n$个数分成$k$组,每个组的值为这个组内不同的数的个数,求$k$个组的值的和的最大值. 题目分析: 这道题我的解法可能和大众解法不太一样……我用主 ...
- Codeforces 813E Army Creation(主席树)
题目链接 Educational Codeforces Round 22 Problem E 题意 给定一个序列,$q$次查询,询问从$l$到$r$中出现过的数字的出现次数和$k$取较小值后的和 ...
- Till I Collapse CodeForces - 786C (主席树区间加,二分最小值)
大意: 给定序列, 将序列划分为若干段, 使得每段不同数字不超过k, 分别求出k=1...n时的答案. 考虑贪心, 对于某个k 从1开始, 每次查询最后一个颜色数<=k的点作为一个划分, 直到全 ...
- 主席树[可持久化线段树](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 ...
- Codeforces Round #276 (Div. 1) E. Sign on Fence (二分答案 主席树 区间合并)
链接:http://codeforces.com/contest/484/problem/E 题意: 给你n个数的,每个数代表高度: 再给出m个询问,每次询问[l,r]区间内连续w个数的最大的最小值: ...
随机推荐
- Hibernate_HelloWord
Hibernate操作步骤 1.新建项目 2.加jar包 3.写XML配置文件hibernate.cfg.xml 4.写log4j.properties日志文件 5.在MySql数据库中建studen ...
- Linux Shell基础 管道符和grep命令
概述 管道符:管道符使用"丨"代表.如"命令1丨命令2".表示命令 1 的正确输出作为命令 2 的操作对象.命令 1 必须有正确输出,而命令 2 必须可以处理命 ...
- 写python中的装饰器
python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器. 首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下) def ...
- java基础—— Collections.sort的两种用法
package com.jabberchina.test; import java.util.ArrayList; import java.util.Collections; import java. ...
- 【Tech】POI标签分类
寒假老板给的任务,让我重现这个实验http://www.liuhaihua.cn/archives/15565.html.自己就随便试了下,用的都是比较经典(lao)的算法和知识,记录一下. 一.从网 ...
- iOS_多线程(一)
在学习多线程之前首先搞清楚以下几个问题. 并发:在同一时刻,只有一条指令被执行,多条指令进行快速切换执行. 并行:在同一时刻,多个处理器可以处理多条指令 1.什么是进程? 一个运行的程序就是 ...
- 教你在windows10环境下如何安装minepy并成功运行!
在学习使用sklearn做单机特征工程这篇文章时,发现在计算互信息时from minepy import MINE代码运行出错ModuleNotFoundError: No module named ...
- mongodb index 的background 及集群的索引建立
在数据库建立索引时,默认时"foreground" 也就是前台建立索引,但是,当你的数据库数据量很大时,在建立索引的时会读取数据文件,大量的文件读写会阻止其他的操作,此时在建立索引 ...
- windows10添加电源计划修改的快捷方案
转自:http://news.mydrivers.com/1/431/431346.htm 由于目前的Windows 10预览版在UI方面还未优化到位,所以某些设置选项要想找出来是很难的,这时候如果能 ...
- 4.JDBC编程
01.JDBC_Java程序和MySQL的关系: 1).Java程序跟其它MySQL客户端一样,就是一个"客户端",用于"封装SQL语句"并发送给MyS ...