K个串
题目链接
题解
看完题目后可以立刻想到:先算出最大值, 然后把最大值剔除掉,再找此时的最大值也就是次大值。这样重复\(k\)边即可找到第\(k\)大值。
于是我们只需要考虑找最大值了
我们可以维护后缀和中的最大值(这里的和是指题目中的不统计重复数字的求和)
具体来说, 我们可以建\(n\)课线段树, 第\(i\)颗存的是以\(i\)为结尾的所有后缀和, 那么, 我们可以把每颗线段树的最大值全部扔进一个大根堆, 这样我们就能每次得到当前的最大值。
接着, 我们从堆中取出当前最大值, 设这个最大值是在第\(i\)棵树的\([l, r]\)区间内取得的, 位置为\(p\), 那么我们分别在第\(i\)棵树的\([l, p)\)和\((p, r]\)两区间内找最大值, 然后把它们放入堆中。
显然, 我们可以用主席树优化空间\((\)pushdown一定要记得复制节点!!!!!\()\)
注意: 由于不统计重复数字, 那么在建主席树时, 设当前数字\(a_i\)上次出现位置为\(l\), 那么它的贡献区间为\((p, i)\)
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long LL;
#define fi first
#define se second
typedef pair <LL, int> pr;
const LL INF = 1e14;
const int N = 100010;
int root[N];
struct SegmentTree
{
int ls[N * 400], rs[N * 400], sz;
LL addv[N * 400];
pr maxv[N * 400];
int cpyNode(int x)
{
int cur = ++sz;
ls[cur] = ls[x];
rs[cur] = rs[x];
maxv[cur] = maxv[x];
addv[cur] = addv[x];
return cur;
}
inline int downtag(int x, LL v)
{
int cur = cpyNode(x);
addv[cur] += v;
maxv[cur].fi += v;
return cur;
}
inline void pushdown(int cur)
{
if (addv[cur])
{
if (ls[cur]) ls[cur] = downtag(ls[cur], addv[cur]);
if (rs[cur]) rs[cur] = downtag(rs[cur], addv[cur]);
addv[cur] = 0;
}
}
void build(int & cur, int l, int r)
{
cur = ++sz;
addv[cur] = 0;
if (l == r) { maxv[cur] = make_pair(0, -l); return; }
int mid = (l + r) >> 1;
build(ls[cur], l, mid);
build(rs[cur], mid+1, r);
maxv[cur] = max(maxv[ls[cur]], maxv[rs[cur]]);
}
void update(int & cur, int pre, int l, int r, int ql, int qr, LL v)
{
if (ql == l && qr == r)
cur = downtag(pre, v);
else
{
pushdown(pre);
cur = cpyNode(pre);
int mid = (l + r) >> 1;
if (qr <= mid)
update(ls[cur], ls[pre], l, mid, ql, qr, v);
else if (ql > mid)
update(rs[cur], rs[pre], mid+1, r, ql, qr, v);
else
update(ls[cur], ls[pre], l, mid, ql, mid, v),
update(rs[cur], rs[pre], mid+1, r, mid+1, qr, v);
maxv[cur] = max(maxv[ls[cur]], maxv[rs[cur]]);
}
}
pr query(int cur, int l, int r, int ql, int qr)
{
if (ql == l && qr == r)
return maxv[cur];
pushdown(cur);
int mid = (l + r) >> 1;
if (qr <= mid)
return query(ls[cur], l, mid, ql, qr);
else if (ql > mid)
return query(rs[cur], mid+1, r, ql, qr);
else
return max(query(ls[cur], l, mid, ql, mid),
query(rs[cur], mid+1, r, mid+1, qr));
}
} seg;
int n, k;
LL a[N]; int last[N];
map <LL, int> pos;
struct Data
{
int id, pl, pr, pos; LL val;
Data() { }
Data(int _1, int _2, int _3, int _4, LL _5) : id(_1), pl(_2), pr(_3), pos(_4), val(_5) { }
bool operator < (const Data & rhs) const { return val < rhs.val; }
};
priority_queue <Data> q;
int main()
{
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
last[i] = pos[a[i]];
pos[a[i]] = i;
}
seg.build(root[0], 1, n);
for (int i = 1; i <= n; i++)
seg.update(root[i], root[i-1], 1, n, last[i]+1, i, a[i]);
for (int i = 1; i <= n; i++)
{
pr res = seg.query(root[i], 1, n, 1, i);
q.push(Data(i, 1, i, -res.se, res.fi));
}
Data res;
for (int i = 1; i <= k; i++)
{
res = q.top(); q.pop();
if (res.pl < res.pos)
{
pr now = seg.query(root[res.id], 1, n, res.pl, res.pos-1);
q.push(Data(res.id, res.pl, res.pos-1, -now.se, now.fi));
}
if (res.pr > res.pos)
{
pr now = seg.query(root[res.id], 1, n, res.pos+1, res.pr);
q.push(Data(res.id, res.pos+1, res.pr, -now.se, now.fi));
}
}
printf("%lld\n", res.val);
return 0;
}
K个串的更多相关文章
- 数据结构(主席树):COGS 2213. K个串
2213. K个串 ★★★★ 输入文件:bzoj_4504.in 输出文件:bzoj_4504.out 简单对比时间限制:20 s 内存限制:512 MB [题目描述] 兔子们在玩k个 ...
- [bzoj P4504] K个串
[bzoj P4504] K个串 [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次 ...
- bzoj : 4504: K个串 区间修改主席树
4504: K个串 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 268 Solved: 110[Submit][Status][Discuss] ...
- 问题 K: 周期串plus
问题 K: 周期串plus 时间限制: 1 Sec 内存限制: 128 MB提交: 682 解决: 237[提交] [状态] [命题人:外部导入] 题目描述 如果一个字符串可以由某个长度为k的字符 ...
- hiho#1449 重复旋律6 求长度为k的串最大次数 后缀自动机
题目传送门 题目大意:求长度为k的串的最大次数,把k从1到length的所有答案全部输出. 思路: 这道题放在$SAM$里就是求长度$k$对应的所有$right$集中最大的大小. 我们以$aabab$ ...
- 【BZOJ4504】K个串 可持久化线段树+堆
[BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...
- bzoj 4504: K个串 可持久化线段树+堆
题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...
- bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)
[fjwc2015]k个串 kstring [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只 ...
- spoj 7258 SUBLEX(求第k大字串
其实对sam的拓扑排序我似懂非懂但是会用一点了. /** @xigua */ #include <stdio.h> #include <cmath> #include < ...
- bzoj 2998 第k小字串
这道题用后缀数组貌似会T. 后缀自动机做法: t==0:第k小的本质不同字串 首先把后缀自动机建出来,我们会得到一个DAG,并且只存在一个点入度为0(我们称之为根),可以证明字符串的任意一个本质不同的 ...
随机推荐
- xml基础之二(XML结构【1】)
xml基础之二(XML结构[1]) 新建 模板 小书匠 XML结构 XML结构 1.1 元素:被开始标签和结束标签所包裹的内容,(红色部分),蓝色部分也是元素,由于其仅有词语和句子,可细分为文本元素 ...
- tab下图表展示宽高为0的问题
tab下,默认展示第一个tab(最新订阅),第二个tab是echarts,需要动态获取父级div的宽高并赋值到图表的DOM的宽高.在实际开发过程中,发现无论如何延迟处理,或者mounted,第二个ta ...
- (转)用C#实现实现简单的 Ping 的功能,用于测试网络是否已经连通
本文转载自:http://blog.csdn.net/xiamin/archive/2009/02/14/3889696.aspx 用C#实现实现简单的 Ping 的功能,用于测试网络是否已经联通 1 ...
- java实现多种加密模式的AES算法-总有一种你用的着
https://blog.csdn.net/u013871100/article/details/80100992 AES-128位-无向量-ECB/PKCS7Padding package com. ...
- MySQL的常用JSON函数
1. JSON_SEARCH(col ->> '$[*].key', type, val) col: JSON格式的字段名 key:要搜索的col字段的key type:可以为'one'或 ...
- unique()与nunique()
1 unique() 统计list中的不同值时,返回的是array.它有三个参数,可分别统计不同的量,返回的都是array. 当list中的元素也是list时,尽量不要用这种方法. import nu ...
- <编译原理 - 函数绘图语言解释器(3)解释器 - python>
<编译原理 - 函数绘图语言解释器(3)解释器 - python> <编译原理 - 函数绘图语言解释器(2)词法分析器 - python> <编译原理 - 函数绘图语言解 ...
- 20191105 《Spring5高级编程》笔记-第9章
第9章 事务管理 一些名词: 2PC(2 Phase Commit) XA协议 JTS(Java Transaction Service) JCA(Java EE Connector Architec ...
- [Web 前端] 001 html 常用块级标签
目录 1. html "总体框架" 2. 常用的 HTML 块级标签(块元素) 2.1 知识点 2.2 以下 code 均写在 body 体中 2.2.1 标题标签,只有 h1-h ...
- 2018年牛客多校寒假 第四场 F (call to your teacher) (图的连通性)
题目链接 传送门:https://ac.nowcoder.com/acm/contest/76/F 思路: 题目的意思就是判断图的连通性可以用可达性矩阵来求,至于图的存储可以用邻接矩阵来储存,求出来可 ...