乙個長度為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
logn)
o(nlogn)
,每次詢問o
(logn
)o(logn)
,共mm
次詢問,總時間複雜度就是o(m
logn)
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取超級和弦,並加入以美妙度從小排到大的優先佇列中。取出堆頂元素,...