单调栈、单调队列及优先队列
1.单调队列
单调队列的描述:指队列中元素之间关系具有单调性,而且队首和队尾都可以出队,但是只有队尾可以进行入队操作。其重要作用是找到前n个后者后n个数的最值。
其具体操作是:假设单调队列是单调递减队列,假设在插入元素v时,将队列尾部的元素同v比较,如果队列尾部的元素不大于元素v,我们直接删除队尾元素,再将队尾元素与v比较,直至队尾元素比v大,这个时候我们将v插入队尾。其实现代码如下:
int que[100]; int head = 0, tail = 0; void push(int a) //进队 { que[++tail] = a; } int pop() //出队 { return que[++head]; } bool empty() //判断队列是否为空 { return !(head < tail); }
下面是求一个整数序列中每k个中的最大值和最小值的代码:
#include<iostream> #include<cstdio> using namespace std; const int maxn=1e6+10; int arr[maxn],que[maxn]; int main() { int n,k; scanf("%d%d",&n,&k); for(int i=1;i<=n;++i) scanf("%d",&arr[i]); int head=1,tail=0; for(int i=1;i<=n;++i){ if(i==1){ que[++tail]=i; } else{ while(head<=tail&&arr[i]<arr[que[tail]]) tail--; que[++tail]=i; if(que[tail]-que[head]>=k) head++; } if(i>=k) printf("%d ",arr[que[head]]); } printf("\n"); head=1,tail=0; for(int i=1;i<=n;++i) { if(i==1) que[++tail]=i; else{ while(head<=tail&&arr[i]>arr[que[tail]]) tail--; que[++tail]=i; if(que[tail]-que[head]>=k) head++; } if(i>=k) printf("%d ",arr[que[head]]); } printf("\n"); }
2.单调栈
顾名思义,单调栈也是保持栈内元素单调递增或单调递减。在插入元素时仍需保持栈内元素的单调性。如现有单调栈,其栈内元素为:1 4 5,这时我们将元素3插入单调栈的话;我们需要先将4 5弹出栈在将3入栈,操作之后栈内元素变为1 3。单调栈似乎也可以通过单调队列实现...
stack<int> S; for(int i=1 ;i<=n ;i++){ while(S.size() && a[S.top()] >= a[i]) S.pop(); if(S.empty()) L[i] = 0; else L[i] = S.top(); S.push(i); }
代码:求最大矩形面积:
#include<bits/stdc++.h> using namespace std; const int maxn = 2010; typedef long long ll; int arr[maxn][maxn], top, st[maxn]; int ans; int L[maxn], R[maxn]; int main() { //ios::sync_with_stdio(false); int n,m; while (scanf("%d%d",&n,&m)!=EOF) { memset(R,0,sizeof(R)); memset(L,0,sizeof(L)); memset(st,0,sizeof(st)); for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) scanf("%d",&arr[i][j]); for (int i =n-1;i>=1;--i) for (int j=1;j<=m;++j) if(arr[i][j]) arr[i][j]+=arr[i+1][j]; ans=-0x3f3f3f3f; for(int i=1;i<=n;++i) { top=0; for(int j=1;j<=m;++j) { while(top>=1&&arr[i][j]<=arr[i][st[top]]) top--; if(!top) L[j]=1; else L[j]=st[top]+1; //在栈顶元素后一位 st[++top]=j; } top = 0; for(int j=m;j>= 1;--j) { while(top>=1&&arr[i][j]<=arr[i][st[top]]) top--; if (!top) R[j]=m; else R[j]=st[top]-1; //在栈顶元素前一位,减一个1 st[++top]=j; } for(int j=1;j<=m;++j) ans=max(ans,arr[i][j]*(R[j]-L[j]+1)); } printf("%d\n",ans); } }
上面求的是最左边第一个比该数小和最右边第一个比该数小的用法,如果要求最右边或最右边第一个比该元素大,只需将while循环里面的<=改为>即可.
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; typedef long long ll; ll arr[maxn],n; ll st[maxn],L[maxn],R[maxn],top; int main() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&arr[i]); top=0; for(int i=1;i<=n;++i) { while(top>=1&&arr[i]>arr[st[top]]) top--; if(!top) L[i]=i; else L[i]=st[top]; st[++top]=i; } top=0; for(int i=n;i>=1;--i) { while(top>=1&&arr[i]>arr[st[top]]) top--; if(!top) R[i]=i; //如果该元素作为次大值没有比它大的,那么最大值和次大值都是它本身 else R[i]=st[top]; //这里不需要加1或者减1,因为这就是比它大的第一个值的下标 st[++top]=i; } ll res=-0x3f3f3f3f; for(int i=1;i<=n;++i){ res=max(res,max(arr[i]^arr[L[i]],arr[i]^arr[R[i]])); } printf("%d\n",res); system("pause"); }
3.优先队列
优先队列是一个队列,优先级高的会先出队列,用法实例:
priority_queue<int> a; priority_queue<node> b; priority_queue<int,vector<int>,greater<int> > c; //注意最后两个>>不能写在一起,加个空格,否则是右移符号,与greater相似的还有less<int>...
在默认情况下,优先队列会自动按降序(从大到小的顺序排列),less
1.优先队列装结构体
有两种排序方式,在结构体外面和在结构体里面:
struct node { int x; int y; bool operator < (cosnt node& t){ return x>t.x; } } bool operator < (const node& a,const node& b) { return a.x>b.x; } //在结构体外面的写法,上例会先输出x较小的
下面是例题代码:
#include<bits/stdc++.h> using namespace std; int n,doct; struct node { int id; //编号 int q; //优先级 friend bool operator < (const node& a,const node& b) { if(a.q==b.q) return a.id>b.id; return a.q<b.q; } //优先级别排序 }pat; priority_queue<node> arr[4]; int main() { ios::sync_with_stdio(0); string str; int cnt=1; while(cin>>n&&n) { cnt=1; for(int i=1;i<=3;i++) { while(!arr[i].empty()) arr[i].pop(); } //初始化 while(n--) { cin>>str; if(str=="IN"){ cin>>doct>>pat.q; pat.id=cnt++; arr[doct].push(pat); } else{ cin>>doct; if(arr[doct].empty()) cout<<"EMPTY"<<endl; else{ cout<<arr[doct].top().id<<endl; arr[doct].pop(); } } } } return 0; }
来源:https://www.cnblogs.com/StungYep/p/12254035.html