analysis
又学到一个新东西:单调栈
话说今天的题怎么全都是新东西,说好的学过的算法呢
单调递增或单调减的栈,跟单调队列差不多,但是只用到它的一端,利用它可以用来解决一些ACM/ICPC和OI的题目,如RQNOJ 的诺诺的队列等。
这个栈本身其实很好说,就是栈里面的元素满足单调递增或单调递减
利用单调栈,我们可以用O(N)的时间复杂度来求解类似下面的问题:
在数组a中,求出所有的L[i]和R[i]
L[i]表示从i向左遍历第一个比a[i]小/大的值的下标
R[i]表示从i向右遍历第一个比a[i]小/大的值的下标
具体如何求解,其实可以简略的理解为lowerbound或upperbound
而本题,只要求到:
L[i]表示从i向左遍历第一个比a[i]小的值的下标
R[i]表示从i向右遍历第一个比a[i]小的值的下标
然后i的次数就是
(
i
−
l
[
i
]
)
×
(
r
[
i
]
−
i
)
(i-l[i])\times(r[i]-i)
(i−l[i])×(r[i]−i)
时间复杂度O(n)
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num); memset(arry,num,sizeof(arry));
#define min(a,b) ((a<b)?a:b)
const int maxn=1000000+10;
int n;
int data[maxn];
long long vis[maxn];
int l[maxn],r[maxn];
inline int read()
{
int _ans=0;bool _neg=false;char _r=getchar();
while(_r>'9'||_r<'0'){if(_r=='-')_neg=true;_r=getchar();}
while(_r>='0'&&_r<='9'){_ans=_ans*10+_r-'0';_r=getchar();}
return (_neg)?-_ans:_ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif
clean(vis,0);
clean(data,0);
clean(l,0);
clean(r,0);
n=read();
loop(i,1,n)data[i]=read();
stack<int>S;
loop(i,1,n)
{
while(S.empty()==false&&data[S.top()]>data[i])
{
S.pop();
}
if(S.empty()==false)
{
l[i]=S.top();
}
S.push(i);
}
while(S.empty()==false)
S.pop();
anti_loop(i,n,1)
{
r[i]=n+1;
while(S.empty()==false&&data[S.top()]>data[i])
{
S.pop();
}
if(S.empty()==false)r[i]=S.top();
S.push(i);
}
loop(i,1,n)
vis[i]=(long long)(i-l[i])*(r[i]-i);
loop(i,1,n)printf("%lld ",vis[i]);
return 0;
}