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

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

考虑顺着做的时候每个点的贡献,如果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. spring boot 在不同环境下读取不同配置文件的一种方式

    在工程中,通常有根据不同的环境读取不同配置文件的需求,对于spring boot 来说,默认读取的是application.yml 或者 application.properties.为了区分不同的环 ...

  2. 支持自定义协议的虚拟仪器【winform版】

    首先,这个程序的由来,额,工作以来,做的最久的就是上位机,对市面上的大部分组态软件都感到不满,不好用,LabView虽然用起来不错,但是入门还是不够简单,刚好现在工作比较闲(已经不再做上位机了),所以 ...

  3. C/C++中连接函数strcat的应用(简单讲解)

    有位学弟问到我如何将两个字符连接起来,想想java/python里面可以直接用+连接起来,可是C/C++里面有没有这么方便的做法呢? 答案是有的,在C语言的string.h库中有个神奇的函数叫做str ...

  4. mysql操作命令梳理(2)-alter(update、insert)

    在mysql运维操作中会经常使用到alter这个修改表的命令,alter tables允许修改一个现有表的结构,比如增加或删除列.创造或消去索引.改变现有列的类型.或重新命名列或表本身,也能改变表的注 ...

  5. Linux运维笔记-日常操作命令总结(2)

    回想起来,从事linux运维工作已近5年之久了,日常工作中会用到很多常规命令,之前简单罗列了一些命令:http://www.cnblogs.com/kevingrace/p/5985486.html今 ...

  6. 阿里云OSS下载pdf文件,并在pdf文件上添加水印

    代码: 兵马未动,粮草先行 作者: 传说中的汽水枪 如有错误,请留言指正,欢迎一起探讨. 转载请注明出处. 公司要求从阿里云OSS下载pdf文件并且需要添加水印. 因此这里总结一下. 首先添加了一个F ...

  7. git学习笔记——廖雪峰git教程

    OK,先附上教程--廖雪峰的官方网站 友情连接:git官网 简介 这里我只想引用他的原文: Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的.实际情况是这样的: L ...

  8. HDU 2075 A|B?

    http://acm.hdu.edu.cn/showproblem.php?pid=2075 Problem Description 正整数A是否能被正整数B整除,不知道为什么xhd会研究这个问题,来 ...

  9. UBB编辑器

    http://ckeditor.com/ 这是老大哥 http://kindeditor.org/ 这是新秀 http://htmleditor.in/firefox-html-editor.html ...

  10. Spring源码阅读学习一

    昨天抽时间阅读Spring源码,先从spring 4.x的core包开始吧,除了core和util里,首当其冲的就是asm和cglib. 要实现两个类实例之间的字段的复制功能: 多年之前用C#,因为阅 ...