D. Max GEQ Sum
time limit per test
1.5 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given an array aa of nn integers. You are asked to find out if the inequality
max(ai,ai+1,…,aj−1,aj)≥ai+ai+1+⋯+aj−1+ajmax(ai,ai+1,…,aj−1,aj)≥ai+ai+1+⋯+aj−1+aj
holds for all pairs of indices (i,j)(i,j), where 1≤i≤j≤n1≤i≤j≤n.
Input
Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤1051≤t≤105). Description of the test cases follows.
The first line of each test case contains a single integer nn (1≤n≤2⋅1051≤n≤2⋅105) — the size of the array.
The next line of each test case contains nn integers a1,a2,…,ana1,a2,…,an (−109≤ai≤109−109≤ai≤109).
It is guaranteed that the sum of nn over all test cases does not exceed 2⋅1052⋅105.
Output
For each test case, on a new line output "YES" if the condition is satisfied for the given array, and "NO" otherwise. You can print each letter in any case (upper or lower).
Example
input
Copy
3
4
-1 1 -1 2
5
-1 2 -3 2 -1
3
2 3 -1
output
Copy
YES YES NO
Note
In test cases 11 and 22, the given condition is satisfied for all (i,j)(i,j) pairs.
In test case 33, the condition isn't satisfied for the pair (1,2)(1,2) as max(2,3)<2+3max(2,3)<2+3.
---------------------------------------------------------------------------------------------------------------------------------
考虑最为暴力的解法,那么很显然就是枚举每个位置i,算i的最坏情况是否满足。
对于每个位置i,其支配的位置,就是其作为最大值的位置,是一个[L,R]区间, 而求数组中距离一个位置最近的大于它的数,考虑使用单调栈,复杂度是线性的,O(N)扫描一遍就能出来结果
这样我们就获得了每个位置的L,R,L为左边第一个大于他的位置,不存在时设置为0,R是第一个大于他的位置,不存在时设置为n+1
然后考虑构造一种最坏情况,因为我们本位置作为其支配区间的最大值,是必须要在区间内的,即其右边要有一段,左边也要有一段,区间和即为右边位置减去左边位置,那么最大区间和就是右边位置的前缀和最大值减去左边位置的前缀和最小值。用线段树暴力维护即可。 值得注意的是,我们 查询的时候 右侧的查询区间为 [i, R[i]-1] 左侧为 [L[i] ,i-1] 因为左侧要被减去,减去sum[L[i]]恰好对应整个左部区间,这是一个小细节
# include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll treemax[200000*4+10],treemin[200000*4+10],sum[200000+10];
void build(int root,int l,int r)
{
if(l==r)
{
treemax[root]=treemin[root]=sum[l];
return ;
}
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
treemax[root]=max(treemax[root<<1],treemax[root<<1|1]);
treemin[root]=min(treemin[root<<1],treemin[root<<1|1]);
}
ll getmax(int root,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
return treemax[root];
int mid=(l+r)>>1;
ll ans=-1e18;
if(L<=mid)
ans=max(ans,getmax(root<<1,l,mid,L,R));
if(R>mid)
ans=max(ans,getmax(root<<1|1,mid+1,r,L,R));
return ans;
}
ll getmin(int root,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
return treemin[root];
int mid=(l+r)>>1;
ll ans=1e18;
if(L<=mid)
ans=min(ans,getmin(root<<1,l,mid,L,R));
if(R>mid)
ans=min(ans,getmin(root<<1|1,mid+1,r,L,R));
return ans;
}
stack<int>s;
int a[200000+10];
int l[200000+10],r[200000+10];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
l[i]=r[i]=i;
}
build(1,0,n+1);
while(!s.empty())
s.pop();
for(int i=1;i<=n;i++)
{
while(!s.empty()&&a[s.top()]<=a[i])
s.pop();
if(!s.empty())
l[i]=s.top();
else
l[i]=0;
s.push(i);
}
while(!s.empty())
s.pop();
for(int i=n;i>=1;i--)
{
while(!s.empty()&&a[s.top()]<=a[i])
s.pop();
if(!s.empty())
r[i]=s.top();
else
r[i]=n+1;
s.push(i);
}
int ans=1;
for(int i=1;i<=n;i++)
{
int nowl=l[i];
int nowr=r[i]-1;
// cout<<i<<" "<<nowr<<" "<<nowl<<" "<<i-1<<endl;
ll maxx=getmax(1,0,n+1,i,nowr);
ll minn=getmin(1,0,n+1,nowl,i-1);
if(maxx-minn>a[i])
{
ans=-1;
break;
}
}
if(ans==-1)
{
cout<<"No"<<endl;
}
else
{
cout<<"YES"<<endl;
}
}
return 0;
}