题目大意:有
n(n≤105)
个塔排成一排,每个塔有一定的初始高度
hi
。 现有操作,对于
l,r(1≤l≤r≤n),d
,能够将
l
到
题解:
显然线段树可以解决。但是区间合并讨论会比较复杂。
可以注意到,对于
hl<hl+1...hk−1<hk>hk+1>...hr−1>hr
,它们的差分的符号函数是非严格递减的。利用差分的性质进行区间合并就省去了很多讨论,只要两个相邻区间的差分满足非严格递减就可以尝试更新答案。每次操作时,只需要维护区间左右端点的差分值即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int l,m,r;
};
node t[3000005];
int arr[300005],n,m;
ll a[300005];//²î·Ö
int sign(long long x)
{
if(x>0)
return 1;
if(x<0)
return -1;
return 0;
}
void cal(int x,int l,int r)
{
int m=(l+r)/2;
t[x].m=max(t[x*2].m,t[x*2+1].m);
t[x].l=t[x*2].l;
t[x].r=t[x*2+1].r;
if(!!a[m]&&!!a[m+1]&&sign(a[m])>=sign(a[m+1]))
{
t[x].m=max(t[x].m,t[x*2].r+t[x*2+1].l);
if(t[2*x].m==m-l+1)
t[x].l=t[2*x].l+t[2*x+1].l;
if(t[2*x+1].m==r-m)
t[x].r=t[2*x].r+t[2*x+1].r;
}
}
void build(int x,int l,int r)
{
if(l==r)
{
int tmp=!!a[l];
t[x]={tmp,tmp,tmp};
return;
}
int m=(l+r)/2;
build(x*2,l,m);
build(x*2+1,m+1,r);
cal(x,l,r);
}
void update(int x,int l,int r,int pos,int d)
{
if(l==r)
{
a[pos]+=d;
int tmp=!!a[pos];
t[x]={tmp,tmp,tmp};
return;
}
int m=(l+r)/2;
if(pos<=m)
update(x*2,l,m,pos,d);
else
update(x*2+1,m+1,r,pos,d);
cal(x,l,r);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
scanf("%d",&arr[i]);
for(int i=0;i+1<n;i++)
a[i]=arr[i+1]-arr[i];
if(n>1)
build(1,0,n-2);
cin>>m;
while(m--)
{
int l,r,d;
scanf("%d%d%d",&l,&r,&d);
if(n==1)
{
printf("%d\n",1);
continue;
}
if(l>1)
update(1,0,n-2,l-2,d);
if(r<n)
update(1,0,n-2,r-1,-d);
printf("%d\n",t[1].m+1);
}
return 0;
}