题意:给你(1e5)长的数组,找任意一个满足以下条件的三元组
分析:很直观的想法,如果暴力枚举+区间优化是N2的,利用要求2的值相等的条件来优化一层循环,直接枚举数的值;
所以:先利用单调栈预处理出每个数的最大最小的左右区间,然后在存储的时候把所有数以《值,位置》用map的方式存下来,然后改变枚举方式,只枚举个数大于等于3的数的位置,加上stl的复杂度可知均摊是Onlogn的;
如何判断存在有解:对于当前枚举的数,发现第一个位置的左值必须是1,同时最后一个位置必须是n——然后枚举中间的位置,只要存在某个位置的左值-1<=第一个值最大的右值,同时右值>=最后一个值的左值,再细节处理一下,这题就过了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+15;
const int mo = 998244353;
#define pb push_back
#define pii pair<int,int>
#define ft first
#define sd second
#define ffor(i,a,b,c) for(int i=(a);i<(b);i+=(c))
#define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
#define rfor(i,a,b,c) for(int i=(a);i>(b);i-=(c))
#define Rfor(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
#define all(x) (x).begin(), (x).end()
#define debug1(x) cerr<<"! "<<x<<endl;
#define debug2(x,y) cerr<<"# "<<x<<" "<<y<<endl;
void slv(){
int n;cin>>n;
vector<int>a(n+1);
map<int,vector<int>>mp;
For(i,1,n,1) {
cin>>a[i];
mp[a[i]].pb(i);
}
stack<pii>st;
vector<pii>mn(n+1); //单调栈就搞清两个事情:一个是维护单调增还是单调减的栈&&正着扫还是倒着扫
vector<pii>mx(n+1);
For(i,1,n,1){
while(!st.empty()&&st.top().sd>a[i]){
auto u=st.top(); st.pop();
mn[u.ft].sd=i-1;
}
st.push({i,a[i]});
}
while(!st.empty()){
auto u=st.top(); st.pop();
mn[u.ft].sd=n;
}
Rfor(i,n,1,1){
while(!st.empty()&&st.top().sd>a[i]){
auto u=st.top(); st.pop();
mn[u.ft].ft=i+1;
}
st.push({i,a[i]});
}
while(!st.empty()){
auto u=st.top(); st.pop();
mn[u.ft].ft=1;
}
For(i,1,n,1){
while(!st.empty()&&st.top().sd<a[i]){
auto u=st.top(); st.pop();
mx[u.ft].sd=i-1;
}
st.push({i,a[i]});
}
while(!st.empty()){
auto u=st.top(); st.pop();
mx[u.ft].sd=n;
}
Rfor(i,n,1,1){
while(!st.empty()&&st.top().sd<a[i]){
auto u=st.top(); st.pop();
mx[u.ft].ft=i+1;
}
st.push({i,a[i]});
}
while(!st.empty()){
auto u=st.top(); st.pop();
mx[u.ft].ft=1;
}
// For(i,1,n,1) cout<<mx[i].ft<<" ++ "<<mx[i].sd<<'\n';
// cout<<endl;
// For(i,1,n,1) cout<<mn[i].ft<<" -- "<<mn[i].sd<<'\n';
// cout<<endl;
int flg=0;
vector<int>ans(3);
for(auto u:mp)if(u.sd.size()>=3){
if(flg) break;
vector<int>tmp=u.sd;
int sz=tmp.size();
int x=tmp[0];
int y=tmp[sz-1];
if(mx[y].sd!=n || mx[x].ft>1) continue;
ffor(i,1,sz-1,1){
if(mn[tmp[i]].ft-1<=mx[x].sd && mn[tmp[i]].sd+1>=mx[y].ft){
flg=1;
ans[0]=min(mx[x].sd,tmp[i]-1);
ans[1]=max(mx[y].ft,tmp[i]);
ans[1]=min({ans[1],mn[tmp[i]].sd,y-1});
ans[2]=n-ans[1];
break;
}
}
}
if(flg){
cout<<"YES\n";
cout<<ans[0]<<" "<<ans[1]-ans[0]<<" "<<ans[2]<<'\n';
return;
}
cout<<"NO\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int t;cin>>t;
while(t--){
slv();
}
}