bzoj4504 K个串 (优先队列+主席树)
首先如果没有出现次数的限制的话,这题就是超级钢琴
但由于有了这个限制,不能简单地用前缀和
考虑顺着做的时候每个点的贡献,如果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个串 (优先队列+主席树)的更多相关文章
- 【BZOJ4504&&Hihocoder1046】K个串(主席树,堆)
题意:一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)询问第k大的和是多少 1 <= n <= 100000, 1 < ...
- bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)
[fjwc2015]k个串 kstring [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只 ...
- luogu2048 [NOI2010]超级钢琴 (优先队列+主席树)
思路:先扫一遍所有点作为右端点的情况,把它们能产生的最大值加到一个优先队列里,然后每次从优先队列里取出最大值,再把它对应的区间的次大值加到优先队列里,这样做K次 可以用一个前缀和,每次找i为右端点的第 ...
- PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值或主席树)
L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有 ...
- 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 ...
- COGS 930. [河南省队2012] 找第k小的数 主席树
主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...
- [xdoj1216]子树第k小(dfs序+主席树)
解题关键:dfs序将树映射到区间,然后主席树求区间第k小,为模板题. #pragma comment(linker, "/STACK:1024000000,1024000000") ...
- HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)
题意:给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少 分析:首先我们先分析单次查询怎么做: 题目给出的数据与多次查询已经在提示着 ...
- K Seq HihoCoder - 1046 || BZOJ4504 k个串
这题与超级钢琴类似,然而重复的不重复计算贡献.. 那么先求出数组nxt,nxt[i]表示第i个元素之后的第一个与其相等的元素的下标,不存在则nxt[i]=0 考虑取的区间左端点为1时的情况. 将读入序 ...
随机推荐
- OI骗分神器——模拟退火算法
前言&&为什么要学模拟退火 最近一下子学了一大堆省选算法,所以搞一个愉快一点的东西来让娱乐一下 其实是为了骗到更多的分,然后证明自己的RP. 说实话模拟退火是一个集物理与IT多方面知识 ...
- [Oracle]包含了MVIEW的表领域,在进行导出,表领域改名,再导入后,MVIEW会消失不见。
包含了MVIEW的表领域,在进行导出,表领域改名,再导入后,MVIEW会消失不见. 测试环境12.1.0.2 =================步骤1:数据的准备 [oracle@db12102 ad ...
- mybatis-高级结果映射之一对一
mybatis的高级结果映射可以很轻松的帮助我们处理一对一, 一对多的数据关系. 1 数据准备 1.1 数据库 创建以下的名为 mybatis 的数据库, 并在其下创建4个表. 在此就不贴出来建表的 ...
- 异步编程(async&await)
前言 本来这篇文章上个月就该发布了,但是因为忙 QuarkDoc 一直没有时间整理,所以耽搁到今天,现在回归正轨. C# 5.0 虽然只引入了2个新关键词:async和await.然而它大大简化了异步 ...
- C#使用FFMPEG推流,并且获取流保存在本地,随时取媒体进行播放!
最近开发了基于C#的推流器一直不大理想,终于在不懈努力之后研究了一点成果,这边做个笔记:本文着重在于讲解下如何使用ffmpeg进行简单的推流,看似简单几行代码没有官方的文档很吃力.并获取流的源代码:如 ...
- SSO单点登录_理解
SSO核心意义就一句话:一处登录,处处登录:一处注销,处处注销.即:在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. 很多人容易把SSO与OAuth搞混.这里简单说明一下: OA ...
- HTTP基础与Android之(安卓与服务器通信)——使用HttpClient和HttpURLConnection
查看原文:http://blog.csdn.net/sinat_29912455/article/details/51122286 1客户端连接服务器实现内部的原理 GET方式和POST方式的差别 H ...
- Beta 冲刺报告模板
Beta 冲刺报告模板 十分钟左右站立会议,控制好时间,不要在此会议上讨论细节问题. 每组一份博客,组内共享,每人都需提交. 模板 队名:xxx 组员1(组长) 过去两天完成了哪些任务 文字/口头描述 ...
- Integer Sequence Dividing CodeForces - 1102A (规律)
You are given an integer sequence 1,2,…,n1,2,…,n. You have to divide it into two sets AAand BB in su ...
- 开源通用爬虫框架YayCrawler-框架的运行机制
这一节我将向大家介绍一下YayCrawler的运行机制,首先允许我上一张图: 首先各个组件的启动顺序建议是Master.Worker.Admin,其实不按这个顺序也没关系,我们为了讲解方便假定是这个启 ...