栈stack
stack<int>ss;
a=ss.top();//返回栈顶的元素
ss.pop();//从栈中取出并删除元素
ss.size();//返回栈中元素个数
ss.push(e);//向栈中添加元素e
ss.empty()://栈为空时返回true
队列queue
queue<int>q;
q.push(x);
a=q.front();
q.pop();
q.empty();
优先队列priority_queue
priority_queue<int,vector<int>,less<int>>q1;//从大到小
priority_queue<int,vector<int>,greater<int>>q2;//从小到大
例1--Buy and Resell
题意:
有n个城市,第i天你会达到第i个城市,在第i个城市中,你可以用ai元购买一个物品,或者用ai元卖掉一个物品,你可以同时保存多个物品。最开始你身上没有物品,但是又无限的金钱,现在要求你从城市1走到城市n,问你最大的收益是多少。
思路:
我们使用优先队列存储我们会考虑进行贸易的城市的价格,优先级为由小到大。
当我们在某个城市选择以a价格买入b价格卖出时,我们向队列里加入两个b,并且把b-a算入利润中。
那么如果在之后的操作中,我们想以a买入以c卖出,我们的实际操作是:
买入队列中的b以c卖出,这时我们的收益是c-b+b-a=c-a,而且还有一个b在队列中。
对于整个模拟过程中,当我们买入的物品为不是之前加入队列的物品则贸易次数+2,否则不交易。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
priority_queue< int,vector<int>,greater<int> > buy,sell;
ll a[maxn];
int main()
{
int n,t;
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
ll ans=0,cnt=0;
for(int i=0;i<n;i++)
{
if(buy.size()!=0&&sell.size()!=0&&buy.top()<sell.top()&&sell.top()<a[i])
{
ans+=a[i];
cnt++;
sell.push(a[i]);
buy.pop();
}
else if(sell.size()!=0&&sell.top()<a[i])
{
buy.push(sell.top());
sell.pop();
sell.push(a[i]);
ans+=a[i]-2*buy.top();
}
else if(buy.size()!=0&&buy.top()<a[i])
{
ans+=a[i];
cnt++;
sell.push(a[i]);
buy.pop();
}
else
{
buy.push(a[i]),ans-=a[i];
}
}
while(!buy.empty())
{
ans+=buy.top();
buy.pop();
}
cout<<ans<<" "<<2*cnt<<endl;
while(!buy.empty())
{
buy.pop();
}
while(!sell.empty())
{
sell.pop();
}
}
}
例2--CF1353D
题意:
给定一个长为n的空数组,将1~n的数字放到数组之中。
放置规则:
- 选择长度最长的空白元素区间,如果有多个,选择最靠左的区间;
- 将 i 放置在 (l+r)/2 的位置;
输出最后的数组。
思路:
拿数字找位置(二分+优先队列)
将空元素区间存储在优先队列之中并设计排序
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
struct node
{
int l,r;
friend bool operator < (node a,node b)
{
if(abs(a.r-a.l)==abs(b.r-b.l))
{
return a.l>b.l;
}
else
{
return abs(a.r-a.l)<abs(b.r-b.l);
}
}
};
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(a,0,sizeof(a));
priority_queue<node>q;
if(n==1)
{
printf("1\n");
}
else
{
q.push({1,n});
int k=1;
while(!q.empty())
{
node tmp=q.top();
q.pop();
int l=tmp.l;
int r=tmp.r;
int mid;
if((r-l+1)%2==0)
mid=(r+l-1)/2;
else
mid=(l+r)/2;
a[mid]=k;
k++;
if((mid-1)>0&&l<(mid-1))
{
q.push({l,mid-1});
}
if(mid<n&&(mid+1)<r)
{
q.push({mid+1,r});
}
}
for(int i=1;i<=n;i++)
{
if(a[i]==0)cout<<k++<<" ";
else cout<<a[i]<<" ";
}
cout<<endl;
}
}
}
双向队列 deque
q.push_front(val);q.pop_front();
q.push_back(val);q.pop_back();
deque模板题
vector数组
1.vector<int> v;
2.v.push_back(1);
3.v.pop_back();//删除尾部元素
4.v.insert(v.begin() + i, a); //在第i + 1个元素前面插入a;
5.v.erase(v.begin() + 2); //删除第3个元素
6.v.erase(v.begin() + i, v.end() + j); //删除区间[i, j - 1]; 区间从0开始
7.v.size();
8.v.clear();
9.reverse(v.begin(), v.end()); //将元素翻转,即逆序排列!
10.sort(v.begin(), v.end()); //(默认是按升序排列, 即从小到大).
multiset
set和multiset会根据特定的排序准则,自动将元素进行排序。不同的是multiset允许元素重复。
(1)定义multiset<int> ms
(2)插入元素k ms.insert(k)
(3)ms.count(k) 元素k在容器内出现的次数(为0表示不在容器中)
(4)ms.erase(k) 删除容器中所有元素k
(5)ms.clear() 清空容器
(6)ms.size() 容器元素个数
(7)ms.empty() 容器是否为空
(8)定义正向迭代器 multiset<int>::iterator it ;
ms.find(k) 寻找k,若找到返回第一个k对应的迭代器,否则返回it.end();
ms.erase(it) 删除迭代器it对应的元素
ms.erase(l, r) 删除迭代器[l, r)之间的元素
lower_bound(k)返回第一个大于等于k的元素的迭代器
upper_bound(k) 返回第一个大于k元素的迭代器
例--Bombing
题意:
现在,在一个1e9×1e9的平面图上有n座城市(n<=100000),系统已经为你提供了它们的坐标。
你有m架轰炸机,每架轰炸机上都携带着病毒炸弹。而每一架轰炸机的飞行模式为c d。
当c=0时,轰炸机将会朝着x=d的方向轰炸城市;
当c=1时,轰炸机将会朝着y=d的方向轰炸城市。
现在你想知道你的每一架轰炸机摧毁了多少城市。
(当城市A被摧毁时,城市A不能再被记入后面的轰炸机战绩之中)
思路:
map<int,multiset<int> > mx,my;
mx[x坐标]=>{y1,y2,y3...} 落在x坐标上的y坐标集合
my[y坐标]=>{x1,x2,x3...} 落在y坐标上的x坐标集合
AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n&&m)
{
int x,y,c,d;
map<int,multiset<int> >ax,ay;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
ax[x].insert(y);
ay[y].insert(x);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&c,&d);
if(c==1)//y=?横着的
{
printf("%d\n",ay[d].size());
multiset<int>::iterator it;
for(it=ay[d].begin();it!=ay[d].end();it++)
{
ax[*it].erase(d);
}
ay[d].clear();
}
else if(c==0)//x=?竖着的
{
printf("%d\n",ax[d].size());
multiset<int>::iterator it;
for(it=ax[d].begin();it!=ax[d].end();it++)
{
ay[*it].erase(d);
}
ax[d].clear();
}
}
printf("\n");
}
}
MAP
1.第一个关键字(key),只能在map中出现一次。
第二个关键字的值(value)
map<int,string>mp;
2. 插入数据
(1)mp.insert(pair<int, string>(1, "one"));
(2)cin>>a>>b;mp[a]=b;
3.map遍历
map<int, string>::iterator it;
for(it=mp.begin();it!=mp.end();it++)
{
int a=it->first;
string b=it->second;
}
4.当所查找的关键key出现时,它返回数据所在对象的位置,如果沒有,返回iter与end函数的值相同。
// find 返回迭代器指向当前查找元素的位置否则返回map::end()位置
it = mp.find("123");
MAP例题
二分查找函数
1、binary_search(beg,end,val)
返回一个bool变量,以二分法在[beg,end]之间查找val,找到返回true,找不到返回false。
2、lower_bound(beg,end,val)
返回一个迭代器,指向非递减序列[first, last)中的第一个大于等于(>=)val的位置。
3、upper_bound(beg,end,val)
返回一个迭代器,指向非递减序列[first, last)中的第一个大于 (>) val的位置。
next_permutation全排列函数
int num[3]={1,2,3};
do
{
cout<<num[0]<<" "<<num[1]<<" "<<num[2]<<endl;
}while(next_permutation(num,num+3));