【无码专区10】第K大查询(双向链表 /主席树+st表)

已自我实现,但还是归入无码专区序列。哈哈哈哈哈

对于my idea部分,我的每一个想法都实现了,可供参考。


problem

给定一个 1∼n1\sim n1n 的排列和 kkk,求所有 r−l+1≥kr-l+1\ge krl+1k 的区间 [l,r][l,r][l,r] 中的第 kkk 大数,输出他们的和。

60%,n≤5e460\%,n\le 5e460%,n5e4

20%,k=120\%,k=120%,k=1

100%,n≤5e5,k≤50100\%,n\le 5e5,k\le 50100%,n5e5,k50

128MB,1s128MB,1s128MB,1s

my idea

注意到 kkk 是非常小的,粗略来看正解应该是 O(nk)O(nk)O(nk) 的。

考虑单独统计每个位置 iii 的贡献。

则需要枚举其左边有 xxx>a[i]>a[i]>a[i] 的数字,右边有 k−x−1k-x-1kx1 个。因为 aia_iai 自己本身还要在前 kkk 大中占据一席位置。

然后需要知道两个端点的位置,记为 l,rl,rl,r。即 [l,i)[l,i)[l,i)>a[i]>a[i]>a[i] 的数有 xxx 个,(i,r](i,r](i,r]>a[i]>a[i]>a[i] 的数有 k−x−1k-x-1kx1 个。

假设 lll 左边,rrr 右边第一个 >a[i]>a[i]>a[i] 的数位置为 L,RL,RL,R

∀p∈(L,l],q∈[r,R)\forall\ p\in(L,l],q\in[r,R) p(L,l],q[r,R) 的区间 [p,q][p,q][p,q] 的答案都会是 a[i]a[i]a[i]

问题就在于怎么快速求得位置左右大于 a[i]a[i]a[i] 个数为 x(1≤x<k)x(1\le x<k)x(1x<k) 的所有位置。

没错——还是主席树!!!

弄两个主席树,一个表示前缀主席树,一个表示后缀主席树。

a[i]a[i]a[i] 建立权值线段树作下标,树上节点权值为下标 iii,维护最大值/最小值。

具体而言:以前缀树为例。

查询:查询前 i−1i-1i1 个树的版本中 [ai+1,n][a_i+1,n][ai+1,n] 的区间中的最大值。表示是最靠近 iii>a[i]>a[i]>a[i] 的位置。

假设这个位置是 ppp,接下来就是在 p−1p-1p1 的版本中查询 [ai+1,n][a_i+1,n][ai+1,n] 的最大值,表示是第二靠近 iii>a[i]>a[i]>a[i] 的位置,以此类推,最多查询到第 k−1k-1k1 靠近就行了。

修改:直接在 i−1i-1i1 的版本上新增将 a[i]a[i]a[i] 对应叶子权值修改为 iii,继续维护最大值。

后缀树与前缀树同理,从后往前做,维护最小值即可。

因为枚举顺序不一样所以是分开做,那么就可以共享同一棵主席树,节省空间。

将每个位置的左右都预处理出来,时间复杂度为 O(nklog⁡n)O(nk\log n)O(nklogn) 的。

对于 60%60\%60% 的数据点 n≤5e4n\le 5e4n5e4,算出来大约是 4e74e74e7 空间也是绰绰有余的。

只不过如果 n≤5e5n\le 5e5n5e5,超时不说,连主席树都开不出来这么大。

#include <bits/stdc++.h>
using namespace std;
#define maxk 52
#define maxn 50002
#define inf 0x3f3f3f3f
int n, k, cnt;
int lst[maxn][maxk], nxt[maxn][maxk];
int a[maxn], root[maxn];
struct node { int ans, lson, rson; } t[maxn * 25];#define mid ( ( l + r ) >> 1 )namespace pre_sgt {void build( int &now, int l, int r ) { t[now = ++ cnt].ans = 0;if( l == r ) return;build( t[now].lson, l, mid );build( t[now].rson, mid + 1, r );}void modify( int pre, int &now, int l, int r, int pos, int k ) {t[now = ++ cnt] = t[pre];if( l == r ) { t[now].ans = k; return; }if( pos <= mid ) modify( t[pre].lson, t[now].lson, l, mid, pos, k );else modify( t[pre].rson, t[now].rson, mid + 1, r, pos, k );t[now].ans = max( t[t[now].lson].ans, t[t[now].rson].ans );}int query( int now, int l, int r, int L ) {if( r < L ) return 0;if( L <= l ) return t[now].ans;return max( query( t[now].lson, l, mid, L ), query( t[now].rson, mid + 1, r, L ) );}
}namespace suf_sgt {void build( int &now, int l, int r ) { t[now = ++ cnt].ans = inf;if( l == r ) return;build( t[now].lson, l, mid );build( t[now].rson, mid + 1, r );}void modify( int pre, int &now, int l, int r, int pos, int k ) {t[now = ++ cnt] = t[pre];if( l == r ) { t[now].ans = k; return; }if( pos <= mid ) modify( t[pre].lson, t[now].lson, l, mid, pos, k );else modify( t[pre].rson, t[now].rson, mid + 1, r, pos, k );t[now].ans = min( t[t[now].lson].ans, t[t[now].rson].ans );}int query( int now, int l, int r, int L ) {if( r < L ) return inf;if( L <= l ) return t[now].ans;return min( query( t[now].lson, l, mid, L ), query( t[now].rson, mid + 1, r, L ) );}
}int main() {freopen( "kth.in", "r", stdin );freopen( "kth.out", "w", stdout );scanf( "%d %d", &n, &k );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );pre_sgt :: build( root[0], 1, n );for( int i = 1;i <= n;i ++ ) {lst[i][0] = i;int pos = i - 1;for( int j = 1;j <= k;j ++ ) {lst[i][j] = pre_sgt :: query( root[pos], 1, n, a[i] + 1 );if( ! lst[i][j] ) break;else pos = lst[i][j] - 1;}pre_sgt :: modify( root[i - 1], root[i], 1, n, a[i], i );}cnt = 0;suf_sgt :: build( root[n + 1], 1, n );memset( nxt, 0x3f, sizeof( nxt ) );for( int i = n;i;i -- ) {nxt[i][0] = i;int pos = i + 1;for( int j = 1;j <= k;j ++ ) {nxt[i][j] = suf_sgt :: query( root[pos], 1, n, a[i] + 1 );if( nxt[i][j] == inf ) break;else pos = nxt[i][j] + 1;}suf_sgt :: modify( root[i + 1], root[i], 1, n, a[i], i );}long long ans = 0;for( int i = 1;i <= n;i ++ ) {for( int j = 0;j < k;j ++ ) {int l = lst[i][j], r = nxt[i][k - j - 1];if( ! l or r == inf ) continue;int posl = max( 1, lst[i][j + 1] + 1 );int posr = min( n, nxt[i][k - j] - 1 );ans += 1ll * ( l - posl + 1 ) * ( posr - r + 1 ) * 1ll * a[i];}}printf( "%lld\n", ans );return 0;
}

注意到还有 20%20\%20% 的额外特殊数据:k=1k=1k=1

这就相当于求每个数为一个区间的最大值的贡献。

显然 [l,r][l,r][l,r] 中最大的数假设在 midmidmid 处,则会将区间划分成独立的两个子区间 [l,mid−1],[mid+1,r][l,mid-1],[mid+1,r][l,mid1],[mid+1,r]

所以可以直接递归处理,对于区间内最大值的贡献自然是 ∀l≤i≤mid≤j≤r\forall\ l\le i\le mid\le j\le r limidjr[i,j][i,j][i,j] 区间都合法。

一个区间内的最大值可以用 st表 预处理出来,查询做到 O(1)O(1)O(1)

每个点就只会被当作最大值算一次,计算也是 O(1)O(1)O(1) 的。

时间复杂度在于 st表 的预处理,O(nlog⁡n)O(n\log n)O(nlogn)

namespace K1 {long long ret = 0;int query( int l, int r ) {int i = log( r - l + 1 ) / log( 2 );if( a[st[l][i]] < a[st[r - ( 1 << i ) + 1][i]] ) return st[r - ( 1 << i ) + 1][i];else return st[l][i]; }void dfs( int l, int r ) {if( l > r ) return;if( l == r ) { ret += a[l]; return; }int mid = query( l, r );ret += 1ll * ( mid - l + 1 ) * ( r - mid + 1 ) * a[mid];dfs( l, mid - 1 );dfs( mid + 1, r );}void solve() {for( int i = 1;i <= n;i ++ ) st[i][0] = i;for( int j = 1;( 1 << j ) <= n;j ++ )for( int i = 1;i + ( 1 << j ) - 1 <= n;i ++ )if( a[st[i][j - 1]] > a[st[i + ( 1 << j - 1 )][j - 1]] )st[i][j] = st[i][j - 1];elsest[i][j] = st[i + ( 1 << j - 1 )][j - 1];dfs( 1, n );printf( "%lld\n", ret );}
}

将这两份代码拼凑在一起,就可以拿到 80′80'80 的高分了。

solution

事实上,我的想法已经非常接近正解了。

只是预处理不是采用主席树自带一个 log⁡\loglog ,而是使用双向链表。

把所有元素从大到小操作,用双向链表连接起来,每次新增一个数就会断掉两个位置的连接,然后加进去再连上。

链表 Li,RiL_i,R_iLi,Ri 记录的是当前对于 iii 而言朝左朝右第一个比 a[i]a[i]a[i] 大的数为止,每次新增数都会维护这个链表。

暴力朝左朝右跳 kkk 次链表,将过程点记录下来,然后就可以枚举 xxx 计算了。

时间复杂度为 O(nk)O(nk)O(nk)

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 500005
#define maxk 55
int n, k;
long long ans;
int lst[maxn], nxt[maxn], L[maxk], R[maxk], a[maxn], id[maxn];
set < int > s;int main() {freopen( "kth.in", "r", stdin );freopen( "kth.out", "w", stdout );scanf( "%d %d", &n, &k );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] ), id[i] = i;sort( id + 1, id + n + 1, []( int x, int y ) { return a[x] > a[y]; } );for( int i = 1;i <= n;i ++ ) {int l = 0, r = 0, cnt_l = 0, cnt_r = 0, Last, Next;auto it = s.lower_bound( id[i] );if( it != s.end() ) r = *it, l = lst[r];else if( ! s.empty() ) l = *-- it, r = nxt[l];s.insert( id[i] );L[0] = R[0] = id[i], Last = l, Next = r;for( int j = 1;j <= k and l;j ++ ) L[++ cnt_l] = l, l = lst[l];for( int j = 1;j <= k and r;j ++ ) R[++ cnt_r] = r, r = nxt[r];if( cnt_l < k ) L[++ cnt_l] = 0;if( cnt_r < k ) R[++ cnt_r] = n + 1;for( l = k - 1, r = 0;~ l;l --, r ++ )if( l < cnt_l and r < cnt_r )ans += 1ll * ( L[l] - L[l + 1] ) * ( R[r + 1] - R[r] ) * a[id[i]];lst[id[i]] = Last, nxt[id[i]] = Next;if( Last ) nxt[Last] = id[i];if( Next ) lst[Next] = id[i];}printf( "%lld\n", ans );return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316743.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SignalR第一节-在5分钟内完成通信连接和消息发送

前言首先声明&#xff0c;这又是一个小白从入门到进阶系列。 SignalR 这个项目我关注了很长时间&#xff0c;中间好像还看到过微软即将放弃该项目的消息&#xff0c;然后我也就没有持续关注了&#xff0c;目前的我项目中使用的是自己搭建的 WebSocket &#xff0c;连接管理和消…

P5327 [ZJOI2019]语言(线段树合并、生成树)

解析 只会扫描线树剖的三只log&#xff08;悲 考虑对每个 uuu 考虑合法的 vvv 的集合&#xff0c;必然是一个联通块。 进一步的&#xff0c;观察到这个联通块就是由所有经过 uuu 的路径的端点形成的最小生成树。 我们有一个最小生成树的经典结论&#xff1a;最小生成树边权和…

【学习笔记】信息学竞赛中的概率与期望小结

信息竞赛——概率与期望事件事件的蕴含、包含事件的互斥事件的对立事件的和&#xff08;并&#xff09;事件的积&#xff08;交&#xff09;事件的差概率事件的独立性全概率公式贝叶斯公式概率DP&#xff08;竞赛中的考察&#xff09;期望&#xff08;竞赛中的考察&#xff09;…

Acwing 218. 扑克牌

Acwing 218. 扑克牌 题意&#xff1a; 一副扑克牌(54张)&#xff0c;问得到A 张黑桃、B 张红桃、C 张梅花、D 张方块需要翻开的牌的张数的期望值 E 是多少&#xff1f; 如果翻开的牌是大王或者小王&#xff0c;Admin 将会把它作为某种花色的牌放入对应堆中&#xff0c;使得放…

尝试:Script Lab,快速 O365 开发工具//SL01)

《前言》Script Lab 我希望有一个系列&#xff08;连载&#xff09;&#xff0c;可是我挺担心没偿没有能力去驾驭它。虽然早年前己经接触过&#xff0c;但一直未有下决心开始 Office 365 的开发之旅&#xff0c;虽然一直被光标老师所鼓舞&#xff0c;但是我心有旁骛还没有真正做…

P3710 方方方的数据结构(kd-tree)

解析 写吐了… 一开始觉得线段树分治直接做就行简直是个伞兵题&#xff0c;写完挂掉才想起来线段树分治会打乱操作顺序导致全假… 重构吧&#xff01; 炸裂之下去贺题解&#xff0c;std做法 O(mmlog⁡m)O(m\sqrt m\log m)O(mm​logm) 令人谔谔&#xff0c;但kd-tree做法确实挺…

[POJ 3709] K-Anonymous Sequence(斜率优化dp / 动态维护凸包)

K-Anonymous Sequence看了两年前自己的博客&#xff0c;真的好青涩&#xff0c;连 markdown 都不太会用。 确实观赏感不是很好。 学习真的是慢慢积累的过程&#xff0c;以前感觉理解很困难的事&#xff0c;随着知识的增长&#xff0c;现在都基本悟了。 problem POJ3709 so…

Keiichi Tsuchiya the Drift King

Keiichi Tsuchiya the Drift King 题意&#xff1a; 给定一辆小车长宽分别为 b&#xff0c;a&#xff0c;轨道的圆弧部分半径为 r&#xff0c;圆弧对应的角度为 d&#xff0c;求出小车能通过轨道的最小轨道宽度 w。 题解&#xff1a; 我们考虑小车处于什么状态会使弯道最宽…

AspNet Core 下利用普罗米修斯+Grafana构建Metrics和服务器性能的监控

概述Prometheus是一套开源的监控&报警&时间序列数据库的组合,起始是由SoundCloud公司开发的。该项目有非常活跃的社区和开发人员&#xff0c;目前是独立的开源项目&#xff0c;现在最常见的Kubernetes容器管理系统中&#xff0c;通常也会搭配Prometheus进行监控。prome…

模板:pb_ds指南

科技改变生活 前言 本来一直被畏于巨长的声明&#xff0c;没有学这个东西… 直到 棘手的操作 这道题&#xff0c;pb_ds模拟实现的两个log的做法不仅好写的一批&#xff0c;连时间竟然也把我单log的左偏树爆踩了&#xff1f;&#xff1f;&#xff1f; … 我选择打不过就加入… …

【学习笔记】多重背包相关优化——二进制优化/单调队列优化

多重背包——二进制优化/单调队列优化二进制优化单调队列优化代码都是 POJ1742 的&#xff0c;注意&#xff0c;那道题二进制优化会超时。 普通的多重背包式子&#xff0c;物品个数限制&#xff1a;c[i]c[i]c[i]&#xff0c;单个物品价值 w[i]w[i]w[i]&#xff0c;每个物品的体…

Game of Swapping Numbers

Game of Swapping Numbers 题意&#xff1a; A&#xff0c;B两个数组&#xff0c;让你对A进行k次操作&#xff0c;每次操作为选两个位置的数&#xff0c;进行交换&#xff0c;求最大化的Σ|Ai-Bi| 题解&#xff1a; 以前有做过最小化的情况&#xff0c;就是把每次交换作定量…

软件工程真的是一门什么用都没有的学科么?

软件工程真的是一门什么用都没有的学科么&#xff1f;-----读《构建之法》有感楔子我很惭愧&#xff0c;构建之法这本书已经出版四五年了&#xff0c;我之前却未曾涉猎&#xff0c;还是在通过组织长沙.net技术社区之后&#xff0c;才因为因缘际遇有幸认识邹欣邹老师之后&#x…

Ball Dropping

Ball Dropping 题意&#xff1a; 求&#xff1f;的具体长度 题解&#xff1a; 算一算就出来了 代码&#xff1a; #include<bits/stdc.h> using namespace std; int main(){double r,a,b,h;cin>>r>>a>>b>>h;if(2*r<b&&2*r<…

[WF2011] MachineWorks(李超树优化dp)

[WF2011]MachineWorksproblem BZOJ3963 solution 来得比较快的是&#xff0c;直接设 dpi,j:dp_{i,j}:dpi,j​: 考虑第 jjj 天换购 iii 机器。 但是马上注意到天数是 1e91e91e9 级别的&#xff0c;而机器是 1e51e51e5 级别。 稍微想想&#xff0c;就能知道&#xff0c;因为…

P3644 [APIO2015]八邻旁之桥(中位数、堆)

前言 卡了很长时间的一个题。 一开始 k1 的关键性质把握就跑偏了&#xff0c;后面基本在硬做… 关键就是一直把每个人当成一条线段作为整体在看&#xff0c;使问题很复杂… 最后用 three-pointers 磕磕绊绊搞出来了。 但是根本不用&#xff01; 解析 这题关键就在于&#xf…

尝试:Script Lab,开发模式之知识储备//SL02

前期00&#xff1a;深度&#xff1a;从 Office 365 新图标来看微软背后的设计新理念前期01&#xff1a;尝试&#xff1a;Script Lab&#xff0c;快速 Office 365 开发工具 //SL01本期02&#xff1a;尝试&#xff1a;Script Lab&#xff0c;开发模式之知识储备 //SL02项目特点适…

【学习笔记】Miller-Rabin(米勒-拉宾)素性测试,附常用表

TOC 素性测试是检验一个给定的整数是否为素数的测试。 最简单的就是用 n\sqrt{n}n​ 以内的数去试除。这是确定性的算法&#xff0c;即能准确知道 nnn 是否为质数。 但今天学习的是一种随机算法。 Fermat 小定理 如果 ppp 是一个质数&#xff0c;且 a%p≠0a\%p≠0a%p​0…

Hash Function

Hash Function 文章目录题意&#xff1a;题解&#xff1a;代码NTT代码FFT代码题意&#xff1a; 给定n个互不相同的数&#xff0c;找一个最小的模域&#xff0c;使得它们在这个模域下互不相同。n<5e5 题解&#xff1a; 考虑两个数a和b&#xff0c;a与b模m余数相同&#xf…

P5321 [BJOI2019]送别(LCT)

Foreword\text{Foreword}Foreword 肝了一下午一晚上的码农题… &#xff08;主要就是在 debug&#xff0c;LCT 太难 de 了…&#xff09; 感谢 M_sea&#xff0c;在调无可调认为LCT会不会不可做时&#xff0c;我看到了他的题解&#xff0c;几乎一样的思路&#xff0c;给了我继…