这些知识总算啃掉了...
重要的思路就是加入栈和队列时还要加入元素的坐标位置。
使用单调栈可以找到元素向左遍历第一个比他小的元素,也可以找到元素向左遍历第一个比他大的元素。
单调栈就简单点,只有栈顶可以操作,若要找到从左到右第一个比i大的数,就保证严格递减,这样如果到第一个比i大的数是i就会被弹出,总之就是找什么条件的数,第i个数被弹出栈的条件就是什么,建议手打栈,代码如下:
n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) { while(top>=1&&a[i]>=q[top].s) ans=ans+i-q[top--].id-1; q[++top].id=i;q[top].s=a[i]; } for(int i=top;i>=1;i--) ans=ans+n-q[top--].id;
单调队列除了tail需要更新,还需要更新head,也就是及时把不符合信息的head出队,、
单调队列性质:
- 1、维护区间最值
- 2、去除冗杂状态 如上题,区间中的两个元素a[i],a[j](假设现在再求最大值)
若 j>i且a[j]>=a[i] ,a[j]比a[i]还大而且还在后面(目前a[j]留在队列肯定比a[i]有用,因为你是往后推, 核心思想 ! - 其中第二条对动态规划仍使用...
与题目联系时,记得把要求的元素放在队头就行了.
例:
for(int i=1;i<=k;i++) { while(head<=tail&&q[tail].s>=a[i]) tail--; q[++tail].id=i,q[tail].s=a[i]; } mn[++o]=q[head].s; for(int i=k+1;i<=n;i++) { while(head<=tail&&q[tail].s>=a[i]) tail--; q[++tail].id=i,q[tail].s=a[i]; while(q[head].id<=i-k) head++; mn[++o]=q[head].s; }
...