STL进阶典题整理 2025.7.30-2025.8.1
题一:序列最值
p1:本题考查priority_queue的重载
p2:题面
初始时,有一个空的序列,接下来会有 n 次操作。
操作一共有三种,每个操作首先用参数op表示第几种操作,具体表示为:
op=1时,再给定一个参数 x,你要向序列插入 x 这个元素。
op=2 时,删除序列中最早插入的元素,输出被删除的这个元素是第几个被插入到序列的。
op=3时,删除序列中数值最大的元素,输出被删除的这个元素是第几个被插入到序列的,特别的,如果有若干个元素都满足值最大这个要求,要删除的元素是最早被插入的元素。
p3:思路
较为明了的一道题, 可以看出需要使用两个大顶堆分别进行op2,op3
p4:重载运算符
能够以试错的方式判断符号,但理解更好
p5:解析与代码
#include<queue>
#include<map>
#include<iostream>
using namespace std;
struct node1{int cs,id;bool operator<(const node1&t)const{//大顶堆重载小于号return id>t.id;//要求最早插入即为id最小的在堆顶//大顶堆排序比较a<b时,即为比较a.id>b.id(b离堆顶更近,a离堆顶更远)//此时比较如果为真,则不需要交换,在比较中更小的b,依然离堆顶更近,实现堆顶更小}
};
struct node2{int cs,id;bool operator<(const node2&t)const{if(cs==t.cs){return id>t.id;//同理}return cs<t.cs;//要求数值最大即为cs最大的在堆顶//大顶堆排序比较a<b时,即为比较a.cs<b.cs(b离堆顶更近,a离堆顶更远)//此时比较如果为真,则不需要交换,在比较中更大的b,依然离堆顶更近,实现堆顶更大}
};
priority_queue<node1>q1;//大顶堆大的在堆顶
priority_queue<node2>q2;
map<int,int>mp;
int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int n,a,b,cnt=0;cin>>n;for(int i=1;i<=n;i++){cin>>a;if(a==1){cin>>b;q1.push({b,++cnt});q2.push({b,cnt});}else if(a==2){while(!q1.empty()&&mp[q1.top().id]==1){//先删除在别的操作中已经删除的数,防止堆顶是已经删除过的数,注意!判空放在前面q1.pop();}printf("%d ",q1.top().id);mp[q1.top().id]=1;q1.pop();}else if(a==3){while(!q2.empty()&&mp[q2.top().id]==1){q2.pop();}printf("%d ",q2.top().id);mp[q2.top().id]=1;q2.pop();}}
}
个人理解在代码注释中,其余均为基础操作
题二:写文章
p1:题面
小可的文艺气息非常浓重,平时的他总喜欢写一些文章。但是苦于没有一个合适的编辑器。
现在小可打算自己动手制作一个文本编辑器用来高效的看文章和写文章。
编辑器是运行在Linux命令行下的,因此只能通过指定的指令进行操作。指令如下:
Insert X
,在当前光标位置插入字符串x。Del
,删除光标前的一个字符串Left
,光标向左移动一下Right
,光标向右移动一下
p2:本题可用两种方式解决
A:两个双端队列(个人更喜欢的版本)
#include<iostream>
#include<queue>
using namespace std;
deque<string>l;
deque<string>r;
int main(){int n;cin>>n;string f,s;for(int i=1;i<=n;i++){cin>>f;if(f=="Insert"){cin>>s;l.push_front(s);}else if(f=="Left"){if(!l.empty()){r.push_back(l.front());l.pop_front();}}else if(f=="Right"){if(!r.empty()){l.push_front(r.back());r.pop_back();}}else{if(!l.empty()){l.pop_front();}}}while(!l.empty()){cout<<l.back()<<" ";l.pop_back();}cout<<"\n";while(!r.empty()){cout<<r.back()<<" ";r.pop_back();}
}
B:对顶栈
#include<iostream>
#include<stack>
using namespace std;
int n,aa;
stack<string> s,ss;
string a[100010];
int main(){string op,s1;cin>>n;while(n--){cin>>op;if(op=="Insert"){cin>>s1;s.push(s1);}else if(op=="Left"){if(!s.empty()){ss.push(s.top());s.pop();}}else if(op=="Right"){if(!ss.empty()){s.push(ss.top());ss.pop();}}else if(op=="Del"){if(!s.empty()){s.pop();}}}while(!s.empty()){a[++aa]=s.top();s.pop();}for(int i=aa;i>=1;i--){cout<<a[i]<<" ";}cout<<endl;while(!ss.empty()){cout<<ss.top()<<" ";ss.pop();}
}
注意结尾输出处理
题三:找小的数字
p1:进阶一下,来到单调栈
由于为典题解析,所以上模板
p2:题目
非常简洁
给定一个N,表示一个序列的长度,然后输入这个序列,输出序列每个元素的左边最近的比它小的数字,如果不存在则输出-1。
#include<iostream>
#include<stack>
using namespace std;
int n,x;
stack<int>st;
int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&x);while(!st.empty()&&x<=st.top()){st.pop();}if(st.empty()){printf("-1 ");}else{printf("%d ",st.top());}st.push(x);}
}