洛谷P2048 超級鋼琴 堆 主席樹

2022-09-01 09:48:10 字數 2261 閱讀 7319

乙個長度為n

n的序列,求m

m個長度在[l,

r][l

,r]之間的子串行,使得這些子串行的元素之和最大。

顯然暴力是很難搞的,考慮先用字首和。

那麼我們要求的就是∑i

=1mm

ax(s

um[k

]−su

m[x−

1])(

x+l−

1≤k≤

x+r−

1)i=

1∑m​

max(

sum[

k]−s

um[x

−1])

(x+l

−1≤k

≤x+r

−1)考慮拆成m

m次詢問。

對於每一次詢問,我們要求max

(sum

[k]−

sum[

x−1]

)max

(sum

[k]−

sum[

x−1]

)。顯然對於固定的xx,s

um[x

−1]s

um[x

−1]也是固定的。所以我們只要求出max

(sum

[k])

max(

sum[

k])即可。而kk

是有範圍要求的。當左端點為x

x時,右端點的區間是固定的。我們每次要在這個區間內求最大,然後再求次大,接下來求第三大。

這顯然就是乙個靜態區間第k

k大的問題。直接主席樹搞定就可以了。

那麼我們要把所有的點作為左端點,然後求出相應的右端點,並插入堆裡。每次取最大值然後維護一下就可以了。

其實這一步就是序列合併了。裡面會講解的更詳細一些。

這樣初始化o(n

log⁡n)

o(nlogn)

,每次詢問o

(log⁡n

)o(logn)

,共mm

次詢問,總時間複雜度就是o(m

log⁡n)

o(mlogn)

。要開lon

glon

glon

glon

g。

#include

#include

#include

#include

#include

#include

#define mp make_pair

using

namespace std;

typedef

long

long ll;

priority_queueint>

> q;

const

int n=

500010

,m=500010*25

;int n,m,l,r,t,tot,root[n]

,num[n]

;ll sum[n]

,b[n]

,ans;

struct tree

tree[m]

;int

build

(int l,

int r)

intinsert

(int now,

int l,

int r,

int k)

intask

(int x,

int y,

int l,

int r,

int k)

//以上主席樹板子

intmain()

sort

(b+1

,b+1

+n);

t=unique

(b+1

,b+1

+n)-b-1;

root[0]

=build(1

,t);

for(

int i=

1;i<=n;i++

) root[i]

=insert

(root[i-1]

,1,t,lower_bound

(b+1

,b+1

+t,sum[i]

)-b)

;for

(int i=

1;i<=n;i++

)while

(m--)}

printf

("%lld\n"

,ans)

;return0;

}

洛谷 P2048 主席樹 區間修改

解題思路 建立主席樹對於第i顆線段樹來說,區間 l,r 表示左端點是l r的點,右端點是i的區間情況,對此第i顆線段樹由i 1顆轉移過來時只需要對當前線段樹進行 1,i 區間都加上a i 的值,那麼這個操作就可以做區間更新,之後就是維護線段樹區間最大值和位置就ok了.然後先把i個最大值插入優先佇列,...

洛谷 P2048 NOI2010 超級鋼琴

給出乙個序列,求和最大的k個連續子串行的和,且連續子串行長度在l與r之間.首先預處理出字首和,我們可以從左端點開始考慮,若左端點為i,則右端點在i l 1與i r 1之間,那麼可以計算出這些區間的最大值,然後放到堆裡去,每次從堆中取出最大值加到ans中後再將該區間左右兩區間的最大值放入堆中.也就是說...

洛谷P2048 NOI2010 超級鋼琴 題解

近期發現這篇題解有點爛,更新一下,刪繁就簡,詳細重點。多加了注釋。就醬紫啦!我們需要先算美妙度的字首和,並初始化rmq。迴圈 i 從 1 到 n 因為以i為起點的和弦終點必定是 i l 1 到 i r 1 之間,所以只要在區間內用rmq取超級和弦,並加入以美妙度從小排到大的優先佇列中。取出堆頂元素,...