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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章