题意:
对于所有的(i,j),满足。
( )
思路:
因为要知道 的值,我们就可以以最大值为,往左和往右分别延伸到第一个比大的数的后一个数和前一个数为一段区间,判断每一个这样的区间是否合法。假设这段区间为[x, y],,先考虑i的左半边,如果区间[x, i-1], [x+1, i-1], ..., [i-1, i-1]中区间和的最大值大于0,那么最大的这段区间和+>,不满足条件;否则,最大的这段区间和+<=。考虑i的右半边也是一样,如果区间[i+1, i+1], ..., [i+1, y-1], [i+1, y]中区间和的最大值大于0,那么也不满足条件。
对于每一个数,求在它后面的、比它大的第一个数:开一个栈和数组(假设它叫res[i],res[i]存放在i之后的、比第i个元素大的第一个数的下标),从前往后遍历数组,如果当前元素比栈顶元素大,那么就记录当前的位置,弹出栈顶,直到栈中没有元素或者栈顶元素大于等于当前元素,将当前元素的下标入栈。
因为需要知道一段区间的最大值,可以用线段树来维护一段区间的最大值。假设线段树的某个点为i,那么i里存放的就是以i为结尾的前缀和,或者以i为开头的后缀和。如果是一条线段[a, b],那么存放的就是以a~b为结尾的前缀和或者以a~b为开头的的最大值。
然后就是一些细节,线段树开多大,初始化线段树等等。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll inf=1e18;
vector<ll> nextGreater(vector<ll> a, int n)
{
stack<ll> st;
vector<ll> res(n, n);
for(int i=0; i<n; i++)
{
while(!st.empty() && a[st.top()]<a[i])
{
res[st.top()]=i;
st.pop();
}
st.push(i);
}
return res;
}
vector<ll> prevGreater(vector<ll> a, int n)
{
stack<ll> st;
vector<ll> res(n, -1);
for(int i=n-1; i>=0; i--)
{
while(!st.empty() && a[st.top()]<a[i])
{
res[st.top()]=i;
st.pop();
}
st.push(i);
}
return res;
}
ll query(vector<ll> &tree, int p, int l, int r, int x, int y)
{
if(y<l || x>r) return -inf;
if(x<=l && r<=y) return tree[p];
int mid=l+(r-l)/2;
ll leftMax=query(tree, p*2, l, mid, x, y);
ll rightMax=query(tree, p*2+1, mid+1, r ,x, y);
return max(leftMax, rightMax);
}
int main(){
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
vector<ll> arr(n);
vector<ll> preSum(n, 0), sufSum(n, 0);
for(int i=0; i<n; i++) cin>>arr[i];
preSum[0]=arr[0];
sufSum[n-1]=arr[n-1];
for(int i=1; i<n; i++) preSum[i]=preSum[i-1]+arr[i];
for(int i=n-2; i>=0; i--) sufSum[i]=sufSum[i+1]+arr[i];
int _n=n;
while(__builtin_popcount(_n)!=1) _n++;
vector<ll> preTree(2*_n, -inf), sufTree(2*_n, -inf);
for(int i=0; i<n; i++)
{
preTree[_n+i]=preSum[i];
sufTree[_n+i]=sufSum[i];
}
for(int i=_n-1; i>=1; i--)
{
preTree[i]=max(preTree[2*i], preTree[2*i+1]);
sufTree[i]=max(sufTree[2*i], sufTree[2*i+1]);
}
vector<ll> neg=nextGreater(arr, n);
vector<ll> preg=prevGreater(arr, n);
bool flag=1;
for(int i=0; i<n; i++)
{
ll rightMax=query(preTree, 1, 0, _n-1, i+1, neg[i]-1)-preSum[i];
ll leftMax=query(sufTree, 1, 0, _n-1, preg[i]+1, i-1)-sufSum[i];
if(max(rightMax, leftMax)>0)
{
flag=0;
break;
}
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}