线段树进阶

线段树3

区间最值&历史最值问题

/*****************************************
Note:
******************************************/
#include <queue>
#include <math.h>
#include <stack>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <iomanip>
#include <string.h>
#include <algorithm>
using namespace std;
#define int long long
#define ls id << 1
#define rs id << 1 | 1
#define read(x) scanf("%lld",&x)
const int N = 2e6 + 10;
const int INF = 0x3f3f3f3f;
struct node
{
	int l , r , A , B , second_num ,cnt , lazy , lazy_second_num , sum ;
	int lazy_old_num , lazy_old_second_num ;

}tr[N];
int n , m , a[N];
void change(int id , int lazy , int lazy_second_num , int lazy_old_num , int lazy_old_second_num)
{
	tr[id].sum += tr[id].cnt * lazy + (tr[id].r - tr[id].l + 1 - tr[id].cnt) * lazy_second_num;

	tr[id].B = max(tr[id].B , tr[id].A + lazy_old_num);

	tr[id].lazy_old_num = max(tr[id].lazy_old_num , tr[id].lazy + lazy_old_num);
	tr[id].lazy_old_second_num = max(tr[id].lazy_old_second_num , tr[id].lazy_second_num + lazy_old_second_num);

	tr[id].A += lazy;
	tr[id].lazy += lazy;
	tr[id].lazy_second_num += lazy_second_num;

	if(tr[id].second_num != -INF)
		tr[id].second_num += lazy_second_num;
}
void push_down(int id)
{
	int maxx = max(tr[ls].A , tr[rs].A);
	if(tr[ls].A == maxx)
		change(ls , tr[id].lazy ,tr[id].lazy_second_num , tr[id].lazy_old_num ,  tr[id].lazy_old_second_num);
	else 
		change(ls , tr[id].lazy_second_num, tr[id].lazy_second_num , tr[id].lazy_old_second_num , tr[id].lazy_old_second_num);

	if(tr[rs].A == maxx)
		change(rs , tr[id].lazy ,tr[id].lazy_second_num , tr[id].lazy_old_num ,  tr[id].lazy_old_second_num);
	else 
		change(rs , tr[id].lazy_second_num, tr[id].lazy_second_num , tr[id].lazy_old_second_num , tr[id].lazy_old_second_num);

	tr[id].lazy = tr[id].lazy_old_num = tr[id].lazy_old_second_num = tr[id].lazy_second_num = 0;
}
void push_up(int id)
{
	tr[id].sum = tr[ls].sum + tr[rs].sum;
	tr[id].A = max(tr[ls].A , tr[rs].A);
	tr[id].B = max(tr[ls].B , tr[rs].B);
	
	if(tr[ls].A == tr[rs].A)
	{
		tr[id].second_num = max(tr[ls].second_num , tr[rs].second_num);
		tr[id].cnt = tr[ls].cnt + tr[rs].cnt;
	}
	else if(tr[ls].A > tr[rs].A)
	{
		tr[id].second_num = max(tr[rs].A , tr[ls].second_num);
		tr[id].cnt = tr[ls].cnt;
	}
	else if(tr[ls].A < tr[rs].A)
	{
		tr[id].second_num = max(tr[ls].A , tr[rs].second_num);
		tr[id].cnt = tr[rs].cnt;
	}
}

void build(int id , int l , int r)
{
	tr[id].l = l , tr[id].r = r;
	tr[id].lazy = tr[id].lazy_second_num = tr[id].lazy_old_num = tr[id].lazy_old_second_num = 0;
	if(l == r)
	{
		tr[id].A = tr[id].B = tr[id].sum = a[l];
		tr[id].second_num = -INF;
		tr[id].cnt = 1;
		return ;
	}
	int mid = (l + r) >> 1;
	build(ls , l , mid);
	build(rs , mid + 1 , r);
	push_up(id);
}


void add_tree(int id ,int l , int r , int x)
{
	if(tr[id].l > r || tr[id].r < l)
		return;
	if(tr[id].l >= l && tr[id].r <= r)
	{
		change(id , x , x, x, x);
		return;
	}
	push_down(id);
	add_tree(ls , l , r , x);
	add_tree(rs , l , r , x);
	push_up(id);
}


void min_tree(int id ,int l , int r , int x)
{
	if(tr[id].l > r || tr[id].r < l || tr[id].A <= x)
		return;
	if(tr[id].l >= l && tr[id].r <= r && tr[id].second_num < x)
	{
		// tr[id].sum -= (tr[id].A - x)*tr[id].cnt;
		// tr[id].lazy -= (tr[id].A - x);
		// tr[id].A = x;
		change(id , x - tr[id].A , 0 , x - tr[id].A  , 0);
		return;
	}
	push_down(id);
	min_tree(ls , l , r , x);
	min_tree(rs , l , r , x);
	push_up(id);
}


int tree_sum(int id, int l , int r)
{
	if(tr[id].l > r || tr[id].r < l)
		return 0;
	if(tr[id].l >= l && tr[id].r <= r)
		return tr[id].sum;
	push_down(id);
	return tree_sum(ls , l , r ) + tree_sum(rs, l , r);
}


int tree_max_A(int id ,int l , int r)
{
	if(tr[id].l > r || tr[id].r < l)
		return -INF;
	if(tr[id].l >= l && tr[id].r <= r)
		return tr[id].A;
	push_down(id);
	return max(tree_max_A(ls, l , r) , tree_max_A(rs , l , r));
}

int tree_max_B(int id ,int l , int r)
{
	if(tr[id].l > r || tr[id].r < l)
		return -INF;
	if(tr[id].l >= l && tr[id].r <= r)
		return tr[id].B;
	push_down(id);
	return max(tree_max_B(ls, l , r) , tree_max_B(rs , l , r));
}
signed main()
{	
	read(n) , read(m);
	for(int i = 1; i <= n ; i++)
		read(a[i]);
	build(1,1,n);
	while(m--)
	{
		int opt , x, y ,k;
		read(opt) , read(x) , read(y);
		if(opt == 1)
			read(k) , add_tree(1,x,y,k);
		else if(opt == 2)
			read(k) , min_tree(1,x,y,k);
		else if(opt == 3)
			printf("%lld\n", tree_sum( 1 , x , y ) );
		else if(opt == 4)
			printf("%lld\n", tree_max_A( 1 , x , y ));
		else 
			printf("%lld\n", tree_max_B( 1 , x , y ));
	}
	return 0;
}

未完成----

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值