Codeforces Round #381 (Div. 1) C

题意:

Alyona造了n座塔。。。。现在要进行m此操作,每次是将[l,r]的塔的高度增加d,

询问每次操作后最长的山峰长度是多少。。

山峰定义为。。。[l,r]内的数,满足al < al+1 < al+2 < .. < amid > .. > ar-2 > ar-1 > ar

长度就是r - l + 1了


solution:

首先对原数列差分,ai = ai+1 - ai

这样山峰就是[l,r]内的数,前面的大于0,后面的小于0,然后长度再+1

这样修改不超过两个数

线段树维护前缀后缀。。。

定义L[o][0]:点o维护的区间内左起最长与左开头数字同号的长度

L[o][1]:点o维护的区间内左起最长与左开头数字先同号后异号的长度

转移写得有点长= =

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 3E5 + 30;
const int T = 4;
typedef long long LL;

int n,m,Max[maxn*T],L[maxn*T][2],R[maxn*T][2];
LL a[maxn],A[maxn],va[maxn*T][2];

int Judge(LL x) 
{
	return x > 0?1:x < 0?-1:0;
}

void maintain(int o,int l,int r)
{
	int lc = (o<<1),rc = (o<<1|1),mid = (l + r) >> 1,tot = 0;
	Max[o] = max(Max[lc],Max[rc]);
	if (Judge(va[lc][1])*Judge(va[rc][0]) > 0)
	{
		if (va[lc][1] > 0) tot = R[lc][0] + L[rc][1];
		else tot = R[lc][1] + L[rc][0];
		Max[o] = max(Max[o],tot);
	}
	else if (va[lc][1] > 0 && va[rc][0] < 0)
	{
		tot = R[lc][0] + L[rc][0];
		Max[o] = max(Max[o],tot);
	}
	if (L[lc][0] == mid - l + 1)
	{
		if (Judge(va[lc][1])*Judge(va[rc][0]) > 0)
		{
			L[o][0] = L[lc][0] + L[rc][0];
			L[o][1] = L[lc][0] + L[rc][1];
		}
		else if (va[lc][1] != 0 && va[rc][0] != 0)
		{
			L[o][0] = L[lc][0];
			L[o][1] = L[lc][0] + L[rc][0];
		}
		else L[o][0] = L[lc][0],L[o][1] = L[lc][1];
	}
	else if (L[lc][1] == mid - l + 1)
	{
		L[o][0] = L[lc][0];
		if (Judge(va[lc][1])*Judge(va[rc][0]) > 0)
			L[o][1] = L[lc][1] + L[rc][0];
		else L[o][1] = L[lc][1];
	}
	else
	{
		L[o][0] = L[lc][0];
		L[o][1] = L[lc][1];
	}
	if (R[rc][0] == r - mid)
	{
		if (Judge(va[lc][1])*Judge(va[rc][0]) > 0)
		{
			R[o][0] = R[rc][0] + R[lc][0];
			R[o][1] = R[rc][0] + R[lc][1];
		}
		else if (va[lc][1] != 0 && va[rc][0] != 0)
		{
			R[o][0] = R[rc][0];
			R[o][1] = R[rc][0] + R[lc][0];
		}
		else R[o][0] = R[rc][0],R[o][1] = R[rc][1];
		
	}
	else if (R[rc][1] == r - mid)
	{
		R[o][0] = R[rc][0];
		if (Judge(va[lc][1])*Judge(va[rc][0]) > 0)
			R[o][1] = R[rc][1] + R[lc][0];
		else R[o][1] = R[rc][1];
	}
	else
	{
		R[o][0] = R[rc][0];
		R[o][1] = R[rc][1];
	}
	va[o][0] = va[lc][0];
	va[o][1] = va[rc][1];
}

void Modify(int o,int l,int r,int pos,LL x)
{
	if (l == r)
	{
		A[l] += x; Max[o] = 1;
		va[o][0] = va[o][1] = A[l];
		L[o][0] = L[o][1] = 1;
		R[o][0] = R[o][1] = 1;
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid) Modify(o<<1,l,mid,pos,x);
	else Modify(o<<1|1,mid+1,r,pos,x);
	maintain(o,l,r);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n;
	for (int i = 1; i <= n; i++) scanf("%I64d",&a[i]);
	for (int i = 1; i < n; i++) 
		a[i] = a[i+1] - a[i],Modify(1,1,n-1,i,a[i]);
	cin >> m;
	while (m--)
	{
		int l,r,x;
		scanf("%d%d%d",&l,&r,&x);
		if (n == 1)
		{
			puts("1");
			continue;
		}
		if (l > 1) Modify(1,1,n-1,l-1,x);
		if (r < n) Modify(1,1,n-1,r,-x);
		printf("%d\n",Max[1] + 1);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值