第四章: 栈、队列(7.21)

栈:

NC14893 栈和排序

保证输出字典序最大,预处理maxx[i]为i~n的最大值

如果当前的数比后面的数都要大的话一定就要在这个时候弹出来

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
int a[1000003],maxx[1000003];
int stackk[1000003];
int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    for(int i=n;i>=1;--i)maxx[i]=max(maxx[i+1],a[i]);
    int top=0;
    for(int i=1;i<=n;++i)
    {
        stackk[++top]=a[i];
        while(top&&stackk[top]>maxx[i+1])
          printf("%d ",stackk[top--]);
    }
}
栈和排序

NC21874 好串

典型栈思想,a则进栈,b就把进了的a出栈

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
char s[103];
int main()
{
    scanf("%s",s+1);
    int l=strlen(s+1);
    int p=0;
    for(int i=1;i<=l;++i)
    {
        if(s[i]=='a')p++;
        else if(s[i]=='b'&&p)p--;
        else {printf("Bad\n");return 0; }
    }
    if(p!=0)printf("Bad\n");
    else printf("Good\n");
}
好串

队列:

NC13822 Keep In Line

使用unordered_map,在此复习一下map和unordered_map(参考博客

与map对比
map

优点:

1.有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作;

2.红黑树,内部实现一个红黑树使得map的很多操作在O(lgn)的时间复杂度下就可以实现,因此效率非常的高。

缺点:空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间

应用场景:对于那些有顺序要求的问题,用map会更高效一些

unordered_map

优点:因为内部实现了哈希表,因此其查找速度非常的快
缺点:哈希表的建立比较耗费时间
应用场景:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map
总结

内存占有率的问题就转化成红黑树 VS Hash表,还是unordered_map占用的内存要高;
但是unordered_map执行效率要比map高很多;
对于unordered_map或unordered_set容器,其遍历顺序与创建该容器时输入的顺序不一定相同,因为遍历是按照哈希表从前往后依次遍历的。

这道题用unordered_map存入字符串到布尔的映射,表示是否访问

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
char s[103];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        unordered_map<string,bool>mp;
        queue<string>q1,q2;
        while(n--)
        {
            string op,name;
            cin>>op>>name;
            if(op=="in")q1.push(name);
            else if(op=="out")q2.push(name);
        }
        int cnt=0;
        while(!q2.empty())
        {
            if(q1.front()==q2.front())cnt++;
            mp[q2.front()]=1;
            while(!q1.empty()&&mp[q1.front()])q1.pop();
            q2.pop();
        }
        printf("%d\n",cnt);
    }
        
        
}
Keep In Line

NC16663 合并果子

做过很多次了,贪心加优先队列,每次合并最小的两堆

NC16430 蚯蚓

开三个队列

原来的长度

分割后更大的一截

分割后更短的一截

显然队列具有单调性,每次取队列的开头即可

每次都要增加的长度,我们可以先不加上,等到取出来的时候再加(i1)q, 放回去的时候注意要减去iq

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
LL a[200005];
queue<LL>Q[3];
int main()
{
    LL n,m,q,u,v,t;scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t);    
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    sort(a+1,a+1+n);
    for(int i=n;i>=1;--i)Q[0].push(a[i]);
    for(int i=1;i<=m;++i)
    {
        LL maxx=-0x3f3f3f3f,pos=-1;
        for(int j=0;j<3;++j)
          if(Q[j].size()&&Q[j].front()>maxx)
          {
              maxx=Q[j].front();
              pos=j;
          }
        Q[pos].pop();
        maxx+=(i-1)*q;
        LL x=maxx*u/v,y=maxx-x;
        if(i%t==0)printf("%lld ",maxx); 
        Q[1].push(x-i*q);//Q[1]存长的那截
        Q[2].push(y-i*q);//Q[2]存短的那截 
    }
    printf("\n");
    int cnt=1;
    while(Q[0].size()||Q[1].size()||Q[2].size())
    {
    //    printf("???%d %d %d\n",Q[0].size(),Q[1].size(),Q[2].size());
        LL p=-0x3f3f3f3f,pos=-1;
        for(int j=0;j<3;++j)
          if(Q[j].size()&&Q[j].front()>p)pos=j,p=Q[j].front();
        Q[pos].pop();
        if(cnt%t==0)printf("%lld ",p+m*q);
        cnt++;
    }
    printf("\n");
}
蚯蚓

双端队列:

NC14661 简单的数据结构

STL中有双端队列deque

push_back(x)/push_front(x) //把x压入后/前端
back()/front() //访问(不删除)后/前端元素
pop_back() pop_front() //删除后/前端元素
empty() //判断deque是否空
size() //返回deque的元素数量
clear() //清空deque
支持通过sort(d.begin(),d.end())进行排序。

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
deque<int>q; 
int main()
{
    int n,T;scanf("%d%d",&n,&T);
    while(T--)
    {
        int op;scanf("%d",&op);
        if(op==1)
        {
            int a;scanf("%d",&a);
            q.push_front(a);
        }
        if(op==2)q.pop_front();
        if(op==3)
        {
            int a;scanf("%d",&a);
            q.push_back(a);
        }
        if(op==4)q.pop_back();
        if(op==5)reverse(q.begin(),q.end());
        if(op==6)
        {
            printf("%d\n",q.size());
            for(int i=0;i<q.size();++i)
              printf("%d ",q[i]);
            printf("\n");
        }
        if(op==7)sort(q.begin(),q.end());
    }
} 
简单的数据结构

单调队列/栈:

NC51001 滑动窗口

 区间长度为k,维护区间最大值最小值

方法一:两个单调队列(经典)

方法二:两个双端队列

min:队头删除的当维护的窗口超过k时,a[i]<q.back,删除尾部的元素

NC24840 look up

对每头牛求出向右看的第一头比它高的牛

 用栈即可

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
int h[100005];
int stackk[100003],ans[100003];
int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&h[i]); 
    int top=0;
    stackk[++top]=1;
    for(int i=2;i<=n;++i)
    {
        if(h[i]<=h[stackk[top]])stackk[++top]=i;
        else
        {
            while(top&&h[stackk[top]]<h[i])ans[stackk[top--]]=i;
            stackk[++top]=i;
        }
    }
    while(top)ans[stackk[top--]]=0;
    for(int i=1;i<=n;++i)printf("%d\n",ans[i]);
}
look up

NC50965 Largest Rectangle in Histogram

求最大矩形覆盖

对于每一列,向左向右找到第一个比它矮的(两个栈处理)

或者更优化一点,就一个从左向右的栈,如果i没有被弹出,说明后面的都比它高,被弹出了说明有一个比它小,也不能往后延伸了,每列在被弹出的时候更新答案。

posted @ 2022-07-24 10:34  yyys  阅读(25)  评论(0编辑  收藏  举报