NC14661 简单的数据结构
题目链接
关键点:
1、因为要实现前后段插入和删除元素,因此用deque
2、有调换头尾的操作,因此我们可以记录一个变量来表示当前是否有调换,这样在进行每一步操作时都得判断一下,排序也得判断是从大到小还是从小到大
完整代码
# include <bits/stdc++.h>
using namespace std;
deque<int>q;
int n, m, t = 1;
bool cmp1(int v1, int v2)
{
return v1<v2;
}
bool cmp2(int v1, int v2)
{
return v1>v2;
}
int main()
{
cin>>n>>m;
for (int i=1; i<=m; i++)
{
int x;
cin>>x;
if (x==1)
{
int data;
cin>>data;
if (t==1)
q.push_front(data);
else
q.push_back(data);
}
if (x==2)
{
if (t==1)
q.pop_front();
else
q.pop_back();
}
if (x==3)
{
int data;
cin>>data;
if (t==1)
q.push_back(data);
else
q.push_front(data);
}
if (x==4)
{
if (t==1)
q.pop_back();
else
q.pop_front();
}
if (x==5)
{
t = -t;
}
if (x==6)
{
cout<<q.size()<<endl;
deque<int>::iterator it;
int a[500010];
int pos = 1;
for (it = q.begin(); it!=q.end(); it++)
{
a[pos++] = *it;
}
if (t==1)
{
for (int i=1; i<pos; i++)
{
if (i<pos-1)
cout<<a[i]<<" ";
else
cout<<a[i];
}
}
else
{
for (int i=pos-1; i>=1; i--)
{
if (i>1)
cout<<a[i]<<" ";
else
cout<<a[i];
}
}
cout<<endl;
}
if (x==7)
{
if (t==1)
sort(q.begin(), q.end(), cmp1);
else
sort(q.begin(), q.end(), cmp2);
}
}
return 0;
}
NC51001 滑动窗口
题目链接
关键点:
1、找k区间内的最小值为例,用一个双端队列deque,先是判断当前维护的区间是否超出k区间大小,如果超出就排除队头元素。然后每次进队时判断一下队尾的元素大小,如果小于队尾元素,又因为该元素位置为该队头元素的后方,所以只要有该元素存在,该队头元素就不可能为k区间内的最小数,就可以直接pop队尾
2、这样循环判断直到找到比队尾小的元素停止,这时如果维护大小包含一个区间,最小值即为队头元素,然后再将该数据存入队尾
3、我们队列存的是数组下标,方便判断该队列的头是否还在区间内
4、为什么队头每次都是该区间最小的数,每次放入队尾的元素都是保证比队头元素大的,该开始时队头即为队尾,且只有比队尾大的数才放入队尾,比队尾小的元素都直接替代队尾元素了,这时继续判断的队尾都会比队头元素大
完整代码
# include <bits/stdc++.h>
using namespace std;
int n, k;
deque<int>d, q;
int a[10000000+10];
int main()
{
cin>>n>>k;
for (int i=1; i<=n; i++)
cin>>a[i];
for (int i=1; i<=n; i++)
{
if (i - q.front()>=k && !q.empty()) q.pop_front();
while (!q.empty() && a[i]<=a[q.back()])
q.pop_back();
q.push_back(i);
if (i>=k) cout<<a[q.front()]<<" ";
}
cout<<endl;
for (int i=1; i<=n; i++)
{
if (i-d.front()>=k && !d.empty()) d.pop_front();
while (!d.empty() && a[i]>=a[d.back()])
d.pop_back();
d.push_back(i);
if (i>=k) cout<<a[d.front()]<<" ";
}
return 0;
}
NC24840 look up
题目链接
关键点:
1、题目要求找每一个点左边第一个大于该点高度的点,因此我们找用栈来维护
2、从最后一个点开始,判断当前元素高度如果大于栈顶元素,就pop,直到找到该栈顶元素会小于该元素为止,这时如果栈有值,那么该top即为该点的仰望对象,如果栈为空,说明该点无仰望对象
3、从最后一个点开始:后面点的仰望对象很明显会影响前面点的
完整代码
# include <bits/stdc++.h>
using namespace std;
int n;
int a[1000000+10];
stack<int>s;
int l[1000000+10];
int main()
{
cin>>n;
for (int i=1; i<=n; i++)
cin>>a[i];
s.push(n);
for (int i=n-1; i>=1; i--)
{
while (!s.empty() && a[i]>=a[s.top()]) s.pop();
if (!s.empty()) l[i] = s.top();
s.push(i);
}
for (int i=1; i<=n; i++)
cout<<l[i]<<endl;
return 0;
}
NC50965 Largest Rectangle in Histogram
题目链接
关键点:
1、该题就是找每一个矩形可以伸长的最大距离,然后乘以该矩形的高度,求这个值的最大值
2、同样的找该矩形往左边和往右边能伸长的最大距离,即是找左边第一个小于该矩形高度的下标和右边第一个小于该矩形高度的下标
完整代码
# include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000000+10;
int n;
int a[1000000+10];
int main()
{
while (1)
{
scanf("%d", &n);
if (!n)
break;
stack<int>l, r;
int le[N], ri[N];
for (int i=1; i<=n; i++)
{
scanf("%d", &a[i]);
}
le[1] = 1;
l.push(1);
for (int i=2; i<=n; i++)
{
while (!l.empty() && a[i]<=a[l.top()]) l.pop();
if (!l.empty()) le[i] = l.top()+1;
else
le[i]=1;
l.push(i);
}
ri[n] = n;
r.push(n);
for (int i=n-1; i>=1; i--)
{
while (!r.empty() && a[i]<=a[r.top()]) r.pop();
if (!r.empty()) ri[i] = r.top()-1;
else
ri[i] = n;
r.push(i);
}
ll maxx = 0;
for (int i=1; i<=n; i++)
{
ll x = a[i]*(ri[i]-le[i]+1);
// cout<<ri[i]<<" "<<le[i]<<endl;
maxx = max(maxx, x);
}
cout<<maxx<<endl;
}
return 0;
}