首先如果没有出现次数的限制的话,这题就是超级钢琴

但由于有了这个限制,不能简单地用前缀和

考虑顺着做的时候每个点的贡献,如果a[i]=x,x上次出现位置是lst[x](可以用一个map来记),那它会给右端点为[i,N],左端点为[lst[x]+1,i]的区间带来x的贡献

根据szr巨佬的说法,主席树的本质就是前缀和套线段树,所以我们如果按区间的右端点建主席树的根,每颗线段树内部存每个位置作为左端点的最大值,只需要给root[i]这棵树上[lst[x]+1,i]做区间+=x就可以了

而且i后面的位置的树还没有建出来,所以不用担心修改以后的更新问题

那么主席树上怎么区间修改呢...对于这道题,只需要像正常的线段树一样pushdown,update,但是每次修改子节点的时候都是新开一个点,然后把信息拷贝过去再修改,在连过去,防止改到前面线段树上的值

然后开优先队列,记下来(x,v,l,r,m)表示右端点为x,在[l,r]的范围内最大值是v,在m取到,每次取出来队顶,然后分割成(x,v',l,m-1,m')和(x,v",m+1,r,m")再塞回队列里,这样做K-1次,最后的队顶就是答案

时空复杂度大概都是$O(nlogn)$的,空间要开大一点。

 #include<bits/stdc++.h>
#define pa pair<ll,int>
#define CLR(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e5+,maxp=maxn*;
const ll inf=1e18; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Node{
int x,l,r,m;ll v;
Node(ll a=,int b=,int c=,int d=,int e=){
v=a,x=b,l=c,r=d,m=e;
}
};
bool operator < (Node a,Node b){return a.v<b.v;} ll laz[maxp];int ch[maxp][],root[maxn],pct;
pa v[maxp];
int N,K;
map<int,int> lst;
priority_queue<Node> q; inline void update(int p){
v[p]=max(v[ch[p][]],v[ch[p][]]);
}
inline int add(int p,ll y){
v[++pct]=v[p];
ch[pct][]=ch[p][],ch[pct][]=ch[p][];
laz[pct]=laz[p]+y;
v[pct].first+=y;
return pct;
}
inline void pushdown(int p){
if(!laz[p]) return;
ch[p][]=add(ch[p][],laz[p]);
ch[p][]=add(ch[p][],laz[p]);
laz[p]=;
} void build(int &p,int l,int r){
p=++pct;
if(l==r) v[p]=make_pair(,l);
else{
int m=l+r>>;
build(ch[p][],l,m);
build(ch[p][],m+,r);
update(p);
}
} void insert(int &p,int pre,int l,int r,int x,int y,int z){
if(x<=l&&r<=y){
p=add(pre,z);
}else{
pushdown(p);
int m=l+r>>;p=++pct;
ch[p][]=ch[pre][],ch[p][]=ch[pre][];
if(x<=m) insert(ch[p][],ch[pre][],l,m,x,y,z);
if(y>=m+) insert(ch[p][],ch[pre][],m+,r,x,y,z);
update(p);
}
} pa query(int p,int l,int r,int x,int y){
pushdown(p);
// printf("%d %d %d %d\n",l,r,x,y);
if(x<=l&&r<=y) return v[p];
else{
int m=l+r>>;pa re=make_pair(-inf,-);
if(x<=m) re=query(ch[p][],l,m,x,y);
if(y>=m+) re=max(re,query(ch[p][],m+,r,x,y));
return re;
}
} int main(){
//freopen("","r",stdin);
int i,j,k;
N=rd(),K=rd();
build(root[],,N);
for(i=;i<=N;i++){
int x=rd();
insert(root[i],root[i-],,N,lst[x]+,i,x);
// printf("mm");
lst[x]=i;
pa re=query(root[i],,N,,i);
// printf("%d %d %d\n",i,re.first,re.second);
q.push(Node(re.first,i,,i,re.second));
}
for(i=;i<K;i++){
Node p=q.top();q.pop();
pa rl,rr;
// pa rl=query(root[p.x],1,N,p.l,p.m-1);
// pa rr=query(root[p.x],1,N,p.m+1,p.r);
if(p.l<p.m) rl=query(root[p.x],,N,p.l,p.m-),q.push(Node(rl.first,p.x,p.l,p.m-,rl.second));
if(p.m<p.r) rr=query(root[p.x],,N,p.m+,p.r),q.push(Node(rr.first,p.x,p.m+,p.r,rr.second));
}
printf("%lld\n",q.top().v);
return ;
}

bzoj4504 K个串 (优先队列+主席树)的更多相关文章

  1. 【BZOJ4504&&Hihocoder1046】K个串(主席树,堆)

    题意:一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)询问第k大的和是多少 1 <= n <= 100000, 1 < ...

  2. bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)

    [fjwc2015]k个串 kstring [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只 ...

  3. luogu2048 [NOI2010]超级钢琴 (优先队列+主席树)

    思路:先扫一遍所有点作为右端点的情况,把它们能产生的最大值加到一个优先队列里,然后每次从优先队列里取出最大值,再把它对应的区间的次大值加到优先队列里,这样做K次 可以用一个前缀和,每次找i为右端点的第 ...

  4. PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值或主席树)

    L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有 ...

  5. SPOJ 10628. Count on a tree (树上第k大,LCA+主席树)

    10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...

  6. COGS 930. [河南省队2012] 找第k小的数 主席树

    主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...

  7. [xdoj1216]子树第k小(dfs序+主席树)

    解题关键:dfs序将树映射到区间,然后主席树求区间第k小,为模板题. #pragma comment(linker, "/STACK:1024000000,1024000000") ...

  8. HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)

    题意:给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少 分析:首先我们先分析单次查询怎么做: 题目给出的数据与多次查询已经在提示着 ...

  9. K Seq HihoCoder - 1046 || BZOJ4504 k个串

    这题与超级钢琴类似,然而重复的不重复计算贡献.. 那么先求出数组nxt,nxt[i]表示第i个元素之后的第一个与其相等的元素的下标,不存在则nxt[i]=0 考虑取的区间左端点为1时的情况. 将读入序 ...

随机推荐

  1. 数列分块入门九题(一):LOJ6277~6279

    Preface 分块,一个神奇的暴力算法.可以把很多\(O(n^2)\)的数据结构题的暴力优化到常数极小的\(O(n\sqrt n)\).当一些毒瘤题无法用线段树,主席树,平衡树,树状数组...... ...

  2. HDU 3400

    一道很适合练习三分的题目三分套三分强不强 题意:给你平面上两条平行线段\(AB\)和\(CD\),一个人要从\(A\)走到\(D\),他在线段\(AB\)上的速度为\(P\),在\(CD\)上的速度为 ...

  3. 开启C语言的学习之门

    本人是一枚工业界的码农,为了职业道路越来越宽广决定向上位机方面进军,C语言曾经在大学里面学过点皮毛但是离应用远远不够,尽量每天在工作之余更新自己学习的进度,同时也希望有大神能给予在编程道路上的指导,话 ...

  4. Python-元组-10

    元祖 Why:对于容器型数据类型list,无论谁都可以对其增删改查,那么有一些重要的数据放在list中是不安全的,所以需要一种容器类的数据类型存放重要的数据,创建之初只能查看而不能增删改,这种数据类型 ...

  5. required: true,el-upload :action="UploadUrl()"

    <el-form-item label="所属班级:" prop="Name" :rules="[{ required: true, messa ...

  6. 基于 CentOS 搭建 FTP 文件服务

    https://www.linuxidc.com/Linux/2017-11/148518.htm

  7. 个人博客Week3——案例分析

    一.调研,评测 我使用的bing的WINDOWS客户端,其大致分为四个模块:词典.例句.翻译.应用. (1)“词典”模块 BUG:搜索”http“词条,界面显示http的相关,但是无法再回到最初的主界 ...

  8. 《Linux内核分析》期终总结

    作者:杨舒雯,原创作品转载请注明出处,<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 目录: 1.通过简 ...

  9. Java实现小学四则运算练习系统(UI)

    github项目地址 :https://github.com/feser-xuan/Arithmetic_test3_UI 小伙伴的博客链接:http://www.cnblogs.com/fukang ...

  10. Beta 冲刺 随笔合集

    团队展示: Team一二一 Beta 冲刺 凡事预则立 Beta冲刺 一 Beta冲刺 二 Beta冲刺 三 Beta冲刺 四 Beta冲刺 五 Beta冲刺 六 Beta冲刺 七 Beta总结 用户 ...