這道線段樹是求最大連續子序列的分治算法的進階版本。它的根本思想還是分治算法,我的算法如下:
1,線段樹的每一個節點保存8個變量(雖然看似很多但是都很有用),分別爲
sum(該區間的和);
maxl(包含該區間最左位置的最大值) , idxl(maxl的最右位置);
同上maxr , idxr ;
mmid(該區間的最大值),midl(最大值的左位置),midr(最大值的右位置) ;
2,如何跟新每一個節點呢?(指由子節點向父節點更新)
太難的寫了,代碼中有詳細的解釋。
3,如何查詢一個區間的maxl,maxr(即答案)?
1,當查詢到一個被完全覆蓋的子區間,那麼該子區間的信息(即保存的8個值)向上傳遞;
2,當查詢到一個區間由兩個子區間合併而來,那麼執行第二步。
要注意題目要求,maxl和maxr儘量小,所以在執行第二步的時候注意是小於大於有沒有等於!!!
然後就是sum等要用long long(因爲這個錯了好幾發) ;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cassert>
using namespace std ;
const int N = 5e5 + 11 ;
typedef long long LL ;
struct Node {
LL sum , maxl , maxr , mmid;
int idxl , idxr , midl , midr ;
};
Node arr[N<<2] ;
int n ;
int x1 , y1 ;
void push_down(Node& site ,const Node& left ,const Node& right) {
site.sum = left.sum + right.sum ;//跟新sum
if(left.sum + right.maxl > left.maxl) {//跟新site的maxl,這裏是小於
site.maxl = left.sum + right.maxl ;
site.idxl = right.idxl ;
}else {
site.maxl = left.maxl ;
site.idxl = left.idxl ;
}
if(right.sum + left.maxr >= right.maxr) {//這裏是等於
site.maxr = right.sum + left.maxr ;
site.idxr = left.idxr ;
}else {
site.maxr = right.maxr ;
site.idxr = right.idxr ;
}
if(left.mmid >= right.mmid) {//這裏是等於
site.mmid = left.mmid ;
site.midl = left.midl ;
site.midr = left.midr ;
}else {
site.mmid = right.mmid ;
site.midl = right.midl ;
site.midr = right.midr ;
}
if(site.mmid <= left.maxr + right.maxl ) {//等於
if(site.mmid == left.maxr + right.maxl && site.midl < left.idxr) return ;
if(site.mmid == left.maxr + right.maxl && site.midl == left.idxr && site.midr < right.idxl) return ;
site.mmid = left.maxr + right.maxl ;
site.midl = left.idxr ;
site.midr = right.idxl ;
}
}
void build(int l , int r , int site) {
if(l == r) {
int a ;
scanf("%d" ,&a);
arr[site].sum = a ;
arr[site].maxl = arr[site].maxr = arr[site].mmid = arr[site].sum ;
arr[site].idxl = arr[site].idxr = arr[site].midl = arr[site].midr = l ;
return ;
}
int mid = (l + r)>>1 ;
build(l , mid , site<<1) ;
build(mid+1 , r , site<<1|1) ;
push_down(arr[site] , arr[site<<1] , arr[site<<1|1]) ;
}
void query(int l , int r , Node& ans , int site) {
if(x1 <= l && r <= y1) {
ans = arr[site] ;
return ;
}
int mid = (l+r)>>1 ;
Node a , b ;
bool f1(false) , f2(false) ;
if(x1 <= mid) {
f1 = true ;
query(l , mid , a , site<<1) ;
}
if(y1 > mid) {
f2 = true ;
query(mid+1, r , b , site<<1|1) ;
}
if(f1&&f2) {
push_down(ans , a , b) ;
}else if(f1) {
ans = a ;
}else ans = b ;
}
int main() {//freopen("data.in" , "r" , stdin) ; freopen("data1.out" , "w" , stdout);
int m , t = 1 ;
while(scanf("%d%d" ,&n ,&m)==2) {
build(1 , n , 1) ;
printf("Case %d:\n" , t++) ;
while(m--) {
scanf("%d%d" ,&x1 ,&y1) ;
Node tmp ;
query(1 , n , tmp , 1) ;
printf("%d %d\n" , tmp.midl , tmp.midr) ;
}
}
}