单调栈
这个神奇的东西,我咕了好久好久。
首先,顾名思义,这个数据结构是个栈,且栈内从栈顶到栈底,一定是单调的。
Q:“道理我都懂,他能干啥?”
A:“$O(n)$求一个数前/后第一个大于/小于他的数。”
Q:“这怎么办呢?"
A:“看这道例题。”
A:“我们维护这个栈,从后往前扫,对于当前的元素,如果栈顶元素小于等于他,就弹出来,一直弹到合法或栈空,那么留下来的不就是第一个大于他的数辣~,然后当前元素入栈即可。”
Q:“这样为什么是对的呢?”
观察这组数据,问题转化为在该位置的人抬头可以看见的最近的人。
所以显然小于等于他且在他右边的人是没有用的,扔掉。
那么不会出现我把最近的比我高的给弹掉了,答案错误吗?
当然不会,首先要明确,轮到我的时候,我的右边一定在栈里面,既然他在栈里面了,假设他比我们大,那肯定是合法答案,那他不超过我们,我们就会弹(其实不难发现是会弹空的,因为我们的栈从栈底到栈顶是严格递增的)。
话不多说,show me the code。
#include<cstdio> #include<queue> #include<cstring> #include<algorithm> #include<vector> #define rep(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i<b;++i) using namespace std; template <typename T> inline void read(T &x){ x=0;char ch=getchar();bool f=0; while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if(f)x=-x; } template <typename T,typename ...Args> inline void read(T &tmp,Args &...tmps){read(tmp);read(tmps...);} const int N = 3e6 + 5; int n,a[N],ans[N],s[N],top; #define now s[top] signed main(){ read(n); rep(i,1,n)read(a[i]); for(int i=n;i>=1;--i){ while(a[i] >= a[now] && top)top--; ans[i] = now; s[++top] = i; } rep(i,1,n)printf("%d ",ans[i]); }