LA 3938 經典線段樹

這道線段樹是求最大連續子序列的分治算法的進階版本。它的根本思想還是分治算法,我的算法如下:

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) ;
		}
	}
}



發佈了48 篇原創文章 · 獲贊 5 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章