基础数据结构
队列
取出放入问题
给一个序列,将最小值x取出,再将f(x)放入
一般f(x)符合某些规律或性质,多开若干个序列维护即可
例1 [P2827] 蚯蚓
例2 [P6033] 合并果子 加强版
堆
例1 P1631序列合并
有两个长度都为n的序列A、B,在A和B中各选一个数相加可以得到n2个数。求这n2个数中最小的n个。
找单调性
A1+B1<=A1+B2<=A1+B3<=…<=A1+Bn
A2+B1<=A2+B2<=A2+B3<=…<=A2+Bn
......
An+B1<=An+B2<=An+B3<=…<=An+Bn
每个序列的队首元素一定为该序列的最小值。
将每个序列的最小元素丢进堆中,删除队首,每取出一个,则加入该序列新的队首
时间复杂度O(nlogn)
对顶堆
提起
然而当只需维护加点、询问操作,且询问有序时,可以用对顶堆
可用于顺序求解第k大数
例1 P1801 黑匣子
维护两个操作
1,ADD(x) 将x加入集合中
2,GET(i)i加1,并输出该集合中第i小的数
维护一个小根堆,一个大根堆,且保证小根堆的堆顶元素大于大根堆的堆顶元素
若此时大根堆中有x个元素,则整个集合中第x大的元素为大根堆堆顶
问题转换为维护两个堆(对顶堆)
例2 求全部子区间的中位数
对每个起点做一遍“黑匣子”即可,时间复杂度
这题还有
栈
P7915 [CSP-S 2021] 回文
P1155 [NOIP2008 提高组] 双栈排序
单调栈
求每个数左面第一个小于等于他的下标位置。
例1
已知
求
#include<iostream>
using namespace std;
const int MAXN=1000000+100;
int n,a[MAXN],ma[MAXN],mi[MAXN],t1=0,t2=0;
long long ans=0;
int main() {
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) {
//for(int j=1;j<=t1;j++) cout<<ma[j]<<' ';cout<<endl;
//for(int j=1;j<=t2;j++) cout<<mi[j]<<' ';cout<<endl;
while(t1-1>0&&a[ma[t1]]<a[i]) {
ans+=1ll*a[ma[t1]]*(ma[t1]-ma[t1-1])*(i-ma[t1]);
t1--;
}
while(t2-1>0&&a[mi[t2]]>a[i]) {
ans-=1ll*a[mi[t2]]*(mi[t2]-mi[t2-1])*(i-mi[t2]);
t2--;
}
if(t1==1&&a[ma[t1]]<a[i]) ans+=1ll*a[ma[t1]]*ma[t1]*(i-ma[t1]),t1--;
if(t2==1&&a[mi[t2]]>a[i]) ans-=1ll*a[mi[t2]]*mi[t2]*(i-mi[t2]),t2--;
ma[++t1]=i;
mi[++t2]=i;
}
for(;t1-1>0;t1--) ans+=1ll*a[ma[t1]]*(ma[t1]-ma[t1-1])*(n-ma[t1]+1);
for(;t2-1>0;t2--) ans-=1ll*a[mi[t2]]*(mi[t2]-mi[t2-1])*(n-mi[t2]+1);
ans+=1ll*a[ma[t1]]*ma[t1]*(n-ma[t1]+1)-1ll*a[mi[t2]]*mi[t2]*(n-mi[t2]+1);
cout<<ans<<endl;
return 0;
}
例2
给定一个1~n的排列A,对于这个排列定义一个函数f(l,r)=max(Al,Al+1..., Ar)请你求出对于所有1≤l≤r≤n,前K大的f(l,r)的和。
注意到,以一个数为最大值的区间,左端点一定在这个数往左最近的一个比它大的数的右边,右端点一定在这个数往右最近的一个比它大的数的左边。因为所给的数列是一个排列,所以不会有相同元素,所以我们对于每一个元素,找到它左边最近的比它大的数的位置i,找到它右边最近的比它大的数的位置jj,设这个数本身位置为k,那么显然以这个数为最大值的区间数量为(k−i)(j−k)个。
单调栈,寻找出每个元素左右第一个比他大的数。
时间复杂度O(n)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通