4504. K个串

  • description
  • solution
  • code

description

兔子们在玩k个串的游戏。首先,它们拿出了一个长度为n的数字序列,选出其中的一

个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)。

兔子们想知道,在这个数字序列所有连续的子串中,按照以上方式统计其所有数字之和,第

k大的和是多少。

Input

第一行,两个整数n和k,分别表示长度为n的数字序列和想要统计的第k大的和

接下里一行n个数a_i,表示这个数字序列

Output

一行一个整数,表示第k大的和

Sample Input

7 5
3 -2 1 2 2 1 3 -2

Sample Output

4

Hint

1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9数据保证存在第 k 大的和

solution

一个[l,r][l,r][l,r]的子串的和定义为不同数的和,一个数多次出现只算一次

可以联想到Rmq Problem / mex的处理

以每个iii为子串右端点rrr建立一个新版本的主席树

每个版本的叶子结点的值就是该点做左端点时,这个子串的和

先继承上一个i−1i-1i−1版本

再记录上一次该值的出现位置lstilst_ilsti​,那么aia_iai​只会对(lsti,i](lst_i,i](lsti​,i]内的数产生aia_iai​贡献

唯一不同的是,这里的修改是对一段区间的修改,为了线段树的复杂度正确必须使用懒标记

而主席树的懒标记,因为某些节点的共用,后面版本的懒标记下传可能会影响前面版本的答案

所以,每个新版本的懒标记下放的时候都需要复制原点,在新点上操作

问题不是求最大,而是第KKK大

这又联想到[NOI]超级钢琴从最佳点进行左右区间切割的处理

先往有先队列里面丢每个版本最大值ans,以及最大值选取的左端点位置pos,还要记录是哪个版本线段树i,以及可选取为左端点的区间l,r

当取出当前的最大值(ans,i,l,r,pos)

就会分裂成两个区间(*,i,l,pos-1,*) (*,i,pos+1,r,*)

*需要对该版本的线段树进行查询,查询区间内的最大值及最大值位置

code

调懒标记的问题,调麻了

#include <map>
#include <queue>
#include <cstdio>
#include <iostream>
using namespace std;
#define Pair pair < int, int >
#define int long long
#define maxn 100005
map < int, int > mp;
struct Node { int ans, i, l, r, pos;bool operator < ( const Node &t ) const {return ans < t.ans;}
};
priority_queue < Node > q;
struct node { int lson, rson, Max, tag, pos; }t[maxn * 160];
int n, k, cnt;
int lst[maxn], a[maxn], root[maxn];void pushup( int now ) {if( t[t[now].lson].Max > t[t[now].rson].Max ) t[now].Max = t[t[now].lson].Max, t[now].pos = t[t[now].lson].pos;elset[now].Max = t[t[now].rson].Max, t[now].pos = t[t[now].rson].pos;
}void pushdown( int now ) {if( ! t[now].tag ) return;node lson = t[t[now].lson];node rson = t[t[now].rson];t[t[now].lson = ++ cnt] = lson;t[t[now].rson = ++ cnt] = rson; t[t[now].lson].Max += t[now].tag;t[t[now].lson].tag += t[now].tag;t[t[now].rson].Max += t[now].tag;t[t[now].rson].tag += t[now].tag;t[now].tag = 0;
}void build( int &now, int l, int r ) {now = ++ cnt;if( l == r ) { t[now].Max = 0, t[now].pos = l; return; }int mid = ( l + r ) >> 1;build( t[now].lson, l, mid );build( t[now].rson, mid + 1, r );pushup( now );
}void modify( int &now, int lst, int l, int r, int L, int R, int val ) {if( r < L or R < l ) return;if( L <= l and r <= R ) {t[now = ++ cnt] = t[lst];t[now].Max += val;t[now].tag += val;return;}pushdown( lst );t[now = ++ cnt] = t[lst];int mid = ( l + r ) >> 1;modify( t[now].lson, t[lst].lson, l, mid, L, R, val );modify( t[now].rson, t[lst].rson, mid + 1, r, L, R, val );pushup( now );
}Pair query( int now, int l, int r, int L, int R ) {if( r < L or R < l ) return make_pair( -1e18, 0 );if( L <= l and r <= R ) return make_pair( t[now].Max, t[now].pos );pushdown( now );int mid = ( l + r ) >> 1;Pair lson = query( t[now].lson, l, mid, L, R );Pair rson = query( t[now].rson, mid + 1, r, L, R );return max( lson, rson );
}signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1;i <= n;i ++ ) {scanf( "%lld", &a[i] );if( mp[a[i]] ) lst[i] = mp[a[i]];mp[a[i]] = i;}build( root[0], 1, n );for( int i = 1;i <= n;i ++ ) {modify( root[i], root[i - 1], 1, n, lst[i] + 1, i, a[i] );Pair it = query( root[i], 1, n, 1, i );q.push( { it.first, i, 1, i, it.second } );}int ans, pos, l, r, i; Pair it;while( k -- ) {Node now = q.top(); q.pop();ans = now.ans, pos = now.pos, i = now.i, l = now.l, r = now.r;if( pos ^ l ) {it = query( root[i], 1, n, l, pos - 1 );q.push( { it.first, i, l, pos - 1, it.second } );}if( pos ^ r ) {it = query( root[i], 1, n, pos + 1, r );q.push( { it.first, i, pos + 1, r, it.second } );}}printf( "%lld\n", ans );return 0;
}

BZOJ4504. K个串(主席树+优先队列)相关推荐

  1. K-th Closest Distance HDU - 6621(第k小绝对值+主席树+二分)

    You have an array: a1, a2, , an and you must answer for some queries. For each query, you are given ...

  2. bzoj4504 K个串

    主席树,先预处理出pre数组,pre[i]表示上一个ai出现的位置,然后假设区间从[1,R-1]变成了[1,R],那么区间[pre[R]+1,R]内的数字需要加上ar,我们按照右端点从小到大建主席树, ...

  3. 【HDU - 2665】Kth number(区间第K大,主席树,模板)

    题干: Give you a sequence and ask you the kth big number of a inteval. Input The first line is the num ...

  4. 主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间=k的个数)...

    取板粗   好东西来的 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/probl ...

  5. CF464E The Classic Problem(主席树+哈希+最短路)

    CF464E The Classic Problem problem solution code problem 题目链接 solution 经典题. 本题很特别的是每条边的边权都是 222 的幂,而 ...

  6. 主席树学习小结(POJ 2104)

    在高中的时候就听到过主席树了,感觉非常高端,在寒假的时候 winter homework中有一题是查找区间第K大的树,当时就开始百度这种网上的博客,发现主席树看不懂,因为那个root[i],还有tx[ ...

  7. SPOJ COT Count on a tree(主席树+倍增lca)

    思路:这个题其实就是树上的第k小,主席树的本质还是类似于前缀和一样的结构,所以是完全相同的,所以我们在树上也可以用同样的方法,我们对于每一个节点进行建树,然后和普通的树上相同,ab之间的距离是等于 r ...

  8. HDU 4417 Super Mario(线段树离线处理/主席树)

    Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...

  9. 【BZOJ4504】K个串 可持久化线段树+堆

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

最新文章

  1. linux提取第一列且删除第一行(awk函数)
  2. SAP Cloud for Customer和SAP S4HANA的Customer - Business partner
  3. HD-SDI DVR发展与应用剖析
  4. Blazor 机制初探以及什么是前后端分离,还不赶紧上车?
  5. c语言全局变量和局部变量作用域重合时,c语言全局变量与局部变量(当变量重名时)的使用情况...
  6. linux网络编程之posix 线程(四):posix 条件变量与互斥锁 示例生产者--消费者问题
  7. VC2013 代码图,依赖项关系图,等出错解决办法.
  8. resnet152训练_Resnet-152的图像预处理
  9. 确保PHP安全 不能违反的四条安全规则
  10. android聊天,存储聊天记录sqlite
  11. python如何将多张excel表内数据求和_Excel批量操作,把你的工作效率提升10倍以上(1)...
  12. C++封装SQLite实例六
  13. java jlist组件_Java中Jlist的Swing组件
  14. 100部超级好电影,100组优秀的字体设计(不看后悔系列)
  15. 校园二手市场需求分析
  16. 用asp.net发送电子邮件
  17. PIE框架基本接口使用方法
  18. fst 共享后缀_trie、FSA、FST(转)
  19. 鸿洋,郭霖Android开发大牛:从入门到精通系列学习路线以及进阶Android高级工程师书籍介绍
  20. java库net2.0下载_visual j 2.0 下载-Visual J# 2.0(vjredist.exe)下载微软官方版-西西软件下载...

热门文章

  1. sql 多表多行模糊查询_从零开始学习SQL(五)多表查询
  2. java中string 和stringbuffer的区别_Java中的String,StringBuilder,StringBuffer三者的区别...
  3. micropython 网络驱动_network_网卡驱动
  4. 有关的命令linux,Linux与用户有关的命令
  5. 51单片机除c语言 中断嵌套,关于51系列单片机中断嵌套 - 关于单片机中断嵌套总结...
  6. linux应用与管理,Linux操作系统应用与管理
  7. java树算法_Java数据结构算法(三)树
  8. 数据结构 - 单调栈、单调队列
  9. 软件构造学习笔记-实验2
  10. 7-7 有重复元素的全排列 (10 分)(set容器做法思路加详解)