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

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

考虑顺着做的时候每个点的贡献,如果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. bitcoin 源码解析 - 交易 Transaction(三) - Script

    bitcoin 源码解析 - 交易 Transaction(三) - Script 之前的章节已经比较粗略的解释了在Transaction体系当中的整体运作原理.接下来的章节会对这个体系进行分解,比较 ...

  2. VS2017一步一步断点调试解决Dapper语句出现的Bug

    最近再做一个项目,出现一个小bug,bug虽小,但是却要命啊.下面我show下我解决问题的方法. View层代码: @model List<mhq.Blog.Model.Blog> < ...

  3. iOS开发简记(2):自定义tabbar

    tabbar是放在APP底部的控件.常见的APP都使用tabbar来进行功能分类的管理,比如微信.QQ等等. 小程需要一个特殊一点的tabbar,要求突显中间的那个按钮,让中间按钮特别显眼,从而引导用 ...

  4. spring-session-data-redis包冲突

    包冲突 spring 的包很容易冲突, 因为写软件的人在兼容性上处理的不够,一般不检测重复加载. spring-session-data-redis 引用后, 一定要把 spring-session ...

  5. 猫咪记单词Beta版使用说明

    猫咪记单词Beta版使用说明 一.项目背景 英语四级考试.六级考试.托福.雅思等英语方面的考试是现在大学生必须面对的问题.同时因为学生对手机的使用越来越频繁,而且仅仅通过书本背诵单词又比较无聊坚持的时 ...

  6. David Silver强化学习Lecture2:马尔可夫决策过程

    课件:Lecture 2: Markov Decision Processes 视频:David Silver深度强化学习第2课 - 简介 (中文字幕) 马尔可夫过程 马尔可夫决策过程简介 马尔可夫决 ...

  7. 修复PLSQL Developer 与 Office 2010的集成导出Excel 功能

    Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.htm]"PerceivedType"="text&qu ...

  8. [转帖]2016年时的新闻:ASP.NET Core 1.0、ASP.NET MVC Core 1.0和Entity Framework Core 1.0

    ASP.NET Core 1.0.ASP.NET MVC Core 1.0和Entity Framework Core 1.0 http://www.cnblogs.com/webapi/p/5673 ...

  9. CentOS 使用SMB服务 让windows能够上传文件

    1. 新增加用户 useradd zhaobsh 2. 使用 pdbedit的方式新增加用户 pdbedit -a -u zhaobsh 3. 修改smb服务 systemctl restart sm ...

  10. python threading模块使用 以及python多线程操作的实践(使用Queue队列模块)

    今天花了近乎一天的时间研究python关于多线程的问题,查看了大量源码 自己也实践了一个生产消费者模型,所以把一天的收获总结一下. 由于GIL(Global Interpreter Lock)锁的关系 ...