bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)
【fjwc2015】k个串 kstring
【题目描述】
兔子们在玩k个串的游戏。首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)。
兔子们想知道,在这个数字序列所有连续的子串中,按照以上方式统计其所有数字之和,第k大的和是多少。
【输入格式】
第一行,两个整数n和k,分别表示长度为n的数字序列和想要统计的第k大的和
接下里一行n个数a_i,表示这个数字序列
【输出格式】
一行一个整数,表示第k大的和
【样例输入】
7 5
3 -2 1 2 2 1 3 -2
【样例输出】
4
【数据范围】
对于20%的数据,1 <= n <= 2000
对于另外20%的数据,0 <= a_i <= 10^9
对于100%的数据,1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9
数据保证存在第k大的和
题解:
理解要紧,很简单的。
一开始以为没有地方可以提交,结果发现bzoj上就有,
可以rt[i]表示以i为左端点的区间。
nxt[i]表示a[i]下一次出现的位置。
发现rt[i]对于rt[i-1],发现就是在i-----nxt[i]-1这些位置都减去a[i],
然后,然后对于i这个位置需要变为-inf,因为无法取到。
然后先建辅助树rt[0],即永久性flag标记打上去的区间修改,然后再以-inf,那个位置再建出
rt[i]即可,然后进行k次操作,用堆来维护即可。
- #include<cstring>
- #include<cmath>
- #include<iostream>
- #include<algorithm>
- #include<cstdio>
- #include<map>
- #include<queue>
- #define lson tr[p].ls
- #define rson tr[p].rs
- #define N 100007
- #define ll long long
- using namespace std;
- const ll inf=;
- inline ll read()
- {
- ll x=,f=;char ch=getchar();
- while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
- while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
- return x*f;
- }
- ll n,k,sz;
- ll a[N],id[N],b[N],rt[N*],nxt[N];
- map<ll,ll>p;
- struct Node
- {
- ll ls,rs,mx,flag,tag;
- }tr[N*];
- struct Date
- {
- ll num,wei,rt;
- friend bool operator < (Date x,Date y)
- {
- return x.num<y.num;
- }
- };
- priority_queue<Date>q;
- bool cmp(ll x,ll y)
- {
- if (a[x]==a[y]) return x<y;
- else return a[x]<a[y];
- }
- inline void update(ll p)
- {
- if (tr[lson].mx+tr[lson].tag>tr[rson].mx+tr[rson].tag) tr[p].mx=tr[lson].mx+tr[lson].tag,tr[p].flag=tr[lson].flag;
- else tr[p].mx=tr[rson].mx+tr[rson].tag,tr[p].flag=tr[rson].flag;
- }
- void build(ll &p,ll l,ll r)
- {
- p=++sz;
- if (l==r)
- {
- tr[p].mx=b[l];
- tr[p].flag=l;
- return;
- }
- ll mid=(l+r)>>;
- build(tr[p].ls,l,mid),build(tr[p].rs,mid+,r);
- update(p);
- }
- void build_new(ll yl,ll &xz,ll l,ll r,ll x,ll y,ll z)
- {
- xz=++sz,tr[xz]=tr[yl];
- if (l==x&&r==y)
- {
- tr[xz].tag+=z;
- return;
- }
- //标记永久化。
- ll mid=(l+r)>>;
- if (y<=mid) build_new(tr[yl].ls,tr[xz].ls,l,mid,x,y,z);
- else if (x>mid) build_new(tr[yl].rs,tr[xz].rs,mid+,r,x,y,z);
- else build_new(tr[yl].ls,tr[xz].ls,l,mid,x,mid,z),build_new(tr[yl].rs,tr[xz].rs,mid+,r,mid+,y,z);
- update(xz);
- }
- int main()
- {
- freopen("kstring.in","r",stdin);
- freopen("kstring.out","w",stdout);
- n=read(),k=read();
- for (ll i=;i<=n;i++)
- a[i]=read(),id[i]=i;
- sort(id+,id+n+,cmp);
- a[]=-inf;
- for (ll i=;i<=n;i++)
- if (a[id[i]]!=a[id[i-]]) b[id[i]]=a[id[i]];
- for (ll i=;i<=n;i++) b[i]+=b[i-];
- build(rt[],,n);
- for (ll i=n;i>=;i--)
- {
- if (!p[a[i]]) nxt[i]=n+;
- else nxt[i]=p[a[i]];
- p[a[i]]=i;
- }
- for (ll i=;i<=n;i++)
- {
- if (i>nxt[i-]-) build_new(rt[i-],rt[],,n,,n,);
- else build_new(rt[i-],rt[],,n,i,nxt[i-]-,-a[i-]);
- build_new(rt[],rt[i],,n,i-,i-,-inf);
- }
- for (ll i=;i<=n;i++)
- q.push((Date){tr[rt[i]].mx+tr[rt[i]].tag,tr[rt[i]].flag,i});
- for(ll i=;i<k;i++)
- {
- Date now=q.top();q.pop();
- build_new(rt[now.rt],rt[n+i],,n,now.wei,now.wei,-inf);
- q.push((Date){tr[rt[n+i]].mx,tr[rt[n+i]].flag,i+n});
- }
- Date now=q.top();
- printf("%lld\n",now.num);
- }
bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)的更多相关文章
- BZOJ4785 [Zjoi2017]树状数组 【二维线段树 + 标记永久化】
题目链接 BZOJ4785 题解 肝了一个下午QAQ没写过二维线段树还是很难受 首先题目中的树状数组实际维护的是后缀和,这一点凭分析或经验或手模观察可以得出 在\(\mod 2\)意义下,我们实际求出 ...
- Codeforces 258E - Little Elephant and Tree(根号暴力/线段树+标记永久化/主席树+标记永久化/普通线段树/可撤销线段树,hot tea)
Codeforces 题目传送门 & 洛谷题目传送门 yyq:"hot tea 不常有,做过了就不能再错过了" 似乎这是半年前某场 hb 模拟赛的 T2?当时 ycx.ym ...
- 51Nod 1175 区间中第K大的数 (可持久化线段树+离散)
1175 区间中第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 一个长度为N的整数序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有 ...
- 【XSY2720】区间第k小 整体二分 可持久化线段树
题目描述 给你你个序列,每次求区间第\(k\)小的数. 本题中,如果一个数在询问区间中出现了超过\(w\)次,那么就把这个数视为\(n\). 强制在线. \(n\leq 100000,a_i<n ...
- P3332 [ZJOI2013]K大数查询(线段树套线段树+标记永久化)
P3332 [ZJOI2013]K大数查询 权值线段树套区间线段树 把插入的值离散化一下开个线段树 蓝后每个节点开个线段树,维护一下每个数出现的区间和次数 为了防止MLE动态开点就好辣 重点是标记永久 ...
- 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)
题意:有N个位置,M个操作.操作有两种,每次操作 如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- bzoj 1513 POI2006 Tet-Tetris 3D 二维线段树+标记永久化
1511: [POI2006]OKR-Periods of Words Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 351 Solved: 220[S ...
- 洛谷P3437 [POI2006]TET-Tetris 3D(二维线段树 标记永久化)
题意 题目链接 Sol 二维线段树空间复杂度是多少啊qwqqq 为啥这题全网空间都是\(n^2\)还有人硬要说是\(nlog^2n\)呀.. 对于这题来说,因为有修改操作,我们需要在外层线段树上也打标 ...
- HFUUOJ1024 动态开点线段树+标记永久化
题意 分析 动态加点线段树,标记永久化好写常数小 Code #include<bits/stdc++.h> #define fi first #define se second #defi ...
随机推荐
- 动态添加出来append的元素加事件
$("body").on("click","#box span",function(){里面执行的东西}) span 是动态添加出来的
- AJPFX讲解java单例模式
单例设计模式概述: 单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. 3 ...
- Python 设计模式--简单工厂模式
简单工厂模式(Factory Pattern)是一种创建型的设计模式,像工厂一样根据要求生产对象实例. 特点:根据不同的条件,工厂实例化出合适的对象. <大话设计模式>中实例:四则运算计算 ...
- 冒泡排序算法和简单选择排序算法的js实现
之前已经介绍过冒泡排序算法和简单选择排序算法和原理,现在有Js实现. 冒泡排序算法 let dat=[5, 8, 10, 3, 2, 18, 17, 9]; function bubbleSort(d ...
- Vue 路由知识三(过渡动画及路由钩子函数)
路由的过渡动画:让路由有过渡动画,需要在<router-view>标签的外部添加<transition>标签,标签还需要一个name属性. <transition nam ...
- SCHTASKS /CREATE
SCHTASKS "/" 这个符号前要加个空格才能运行成功 ,搞半天!
- jquery 移动端 六位密码输入
<!DOCTYPE html> <html> <head> <script src="scripts/jquery-1.7.1.min.js&quo ...
- CSS3 动画-- 鼠标移上去,div 会旋转、放大、移动
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- PHP 下基于 php-amqp 扩展的 RabbitMQ 简单用例 (一) -- 安装 AMQP 扩展和 Direct Exchange 模式
Windows 安装 amqp 扩展 RabbitMQ 是基于 amqp(高级消息队列协议) 协议的.使用 RabbitMQ 前必须为 PHP 安装相应的 amqp 扩展. 下载相应版本的 amqp ...
- 使用HTML5+调用手机摄像头和相册
前言:前端时间使用HTML5做了一个WEB端APP,其中用到了H5页面调用手机摄像头的功能,当时也是花了不少时间去研究.最终是采用了HTML5plus(HTML5+)的方式完成了该功能,现将具体方法简 ...