T1:luogu:P3613
超市里有 n(1\le n\le10^5)n(1≤n≤105) 个寄包柜。每个寄包柜格子数量不一,第 ii 个寄包柜有 a_i(1\le a_i\le10^5)ai(1≤ai≤105) 个格子,不过我们并不知道各个 a_iai 的值。对于每个寄包柜,格子编号从 1 开始,一直到 a_iai。现在有 q(1 \le q\le10^5)q(1≤q≤105) 次操作:
1 i j k
:在第 ii 个柜子的第 jj 个格子存入物品 k(0\le k\le 10^9)k(0≤k≤109)。当 k=0k=0 时说明清空该格子。2 i j
:查询第 ii 个柜子的第 jj 个格子中的物品是什么,保证查询的柜子有存过东西。
已知超市里共计不会超过 10^7107 个寄包格子,a_iai 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然也有可能某些寄包柜中一个格子都没有。
输入格式
第一行 2 个整数 nn 和 qq,寄包柜个数和询问次数。
接下来 qq 个整数,表示一次操作。
输出格式
对于查询操作时,输出答案,以换行隔开。
输入输出样例
输入 #1复制
5 4 1 3 10000 118014 1 1 1 1 2 3 10000 2 1 1
输出 #1复制
118014 1
思路:既然学了一点数据结构,那就浅浅的用map来做,读入寄包柜个数n和询问次数q后,再读入依次读入操作x(1或0),以及对应的柜子(gui),格子(ge),如果x==1,继续读入k,将对应的柜子中格子,改为k;如果x==0,输出对应的查询结果
主要是用map的一些基本操作:
- map<key,elem> 名称;(默认以less<>排序为标准)
- map<key, elem,op> 名称;(以op排序为标准)
首先map是stl内置的一个容器,健-值对的集合(不允许重复的元素),其中key相当于一个身份证,通过这个身份证,可以查询到你的种种信息,当然map本身也可以作为数据类型本身(类似vector实现二维数组)
然后是它的一些操作(时间复杂度为log2N)
1:map的大小:map.size();
2:判断map是否为空:map.empty(),若为空返回true,反之为false
函数原型:bool empty ();
3:遍历map:map不支持元素直接存取,需要通过迭代器实现
函数:
- begin()【指向第一个元素】
- end()【指向最后一个元素的下一个元素】
- rbegin()【指向最后一个元素】
- rend()【指向第一个元素】,加个r相当于反向迭代。
4:map元素的插入和删除:
- 插入:insert()函数,分为三种形式:
- 第一种:map.insert(elem)将元素插入到map的末尾
- 第二种:map.insert (iterator it,elem)将元素elem插入到迭代器it之前
- 第三种:map.insert(first,last)将迭代器(first,last)指定范围的元素插入到map
- 删除:erase();
全部删除:clear();
#include<bits/stdc++.h>
using namespace std;
map<int,map<int,int> > v;
int n,q,gui,ge,w;
int main()
{
cin>>n>>q;
for(int i=1;i<=q;i++)
{
int x;
cin>>x>>gui>>ge;
if(x==1){
cin>>w;
v[gui][ge]=w;
}
else if(x==2){
cout<<v[gui][ge]<<endl;
}
}
return 0;
}
T2:括号序列
定义如下规则:
- 空串是「平衡括号序列」
- 若字符串 SS 是「平衡括号序列」,那么 \texttt{[}S\texttt][S] 和 \texttt{(}S\texttt)(S) 也都是「平衡括号序列」
- 若字符串 AA 和 BB 都是「平衡括号序列」,那么 ABAB(两字符串拼接起来)也是「平衡括号序列」。
例如,下面的字符串都是平衡括号序列:
()
,[]
,(())
,([])
,()[]
,()[()]
而以下几个则不是:
(
,[
,]
,)(
,())
,([()
现在,给定一个仅由 (
,)
,[
,]
构成的字符串 ss,请你按照如下的方式给字符串中每个字符配对:
- 从左到右扫描整个字符串。
- 对于当前的字符,如果它是一个右括号,考察它与它左侧离它最近的未匹配的的左括号。如果该括号与之对应(即小括号匹配小括号,中括号匹配中括号),则将二者配对。如果左侧未匹配的左括号不存在或与之不对应,则其配对失败。
配对结束后,对于 ss 中全部未配对的括号,请你在其旁边添加一个字符,使得该括号和新加的括号匹配。
输入格式
输入只有一行一个字符串,表示 ss。
输出格式
输出一行一个字符串表示你的答案。
输入输出样例
输入 #1复制
([()
输出 #1复制
()[]()
思路:用一个int类型的栈储存对应左括号的序号,当右括号来临,且对应的左括号,左括号的序列恰好在栈顶的位置,我们将这两个括号分别标记为1,代表已经匹配,在输出时候就无需额外操作,直接输出,对于未匹配的括号,我们在输出时输出完整的一对括号。
#include<bits/stdc++.h>
using namespace std;
string s;
stack <int> sta;
bool match[105];
int main()
{
cin>>s;
int n=s.length();
for(int i=0;i<n;i++){
if(s[i]==')')//如果为右小括号,寻找栈顶是否为左小括号
{
if(sta.empty())continue;//如果栈为空,显然不能匹配 ,标记为false
if(s[sta.top()]=='(')match[i]=1,match[sta.top()]=1,sta.pop();//匹配成功,将栈顶的这个左括号标记为ture,移除栈
}
else if(s[i]==']')//如果为右中括号,寻找栈顶是否为右中括号
{
if(sta.empty())continue;//如果栈为空,显然不能匹配 ,标记为false
if(s[sta.top()]=='[')match[i]=1,match[sta.top()]=1,sta.pop();
}
else sta.push(i);
}
for(int i=0;i<n;i++)
{
if(match[i])cout<<s[i];//如果已经匹配了直接输出
else{//没有匹配输出对应括号
if(s[i]==')'||s[i]=='(')cout<<"()";
if(s[i]=='['||s[i]==']')cout<<"[]";
}
}
return 0;
}
T3:后缀表达式
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。
如:\texttt{3*(5-2)+7}3*(5-2)+7 对应的后缀表达式为:\texttt{3.5.2.-*7.+@}3.5.2.-*7.+@。在该式中,@
为表达式的结束符号。.
为操作数的结束符号。
输入格式
输入一行一个字符串 ss,表示后缀表达式。
输出格式
输出一个整数,表示表达式的值。
输入输出样例
输入 #1复制
3.5.2.-*7.+@
输出 #1复制
16
思路:同样的,我们用一个int类型的栈储存,输入的数字,当遇到运算符,依次取出并删除栈顶B,及栈顶下面的一个元素A,然后A operate
B,然后将操作的结果放置于栈顶。
#include<bits/stdc++.h>
using namespace std;
stack <int> sta;
string s;
int main()
{
cin>>s;
int n=s.length(),t=0;
for(int i=0;i<n;i++){
//cout<<"读入的字符为"<<s[i]<<' ';
if(s[i]>='0'&&s[i]<='9')//如果输入的是数字
{
t*=10;
t+=(s[i]-'0');
}
else if(s[i]=='.'){
//cout<<"入栈的数字"<<t<<endl;
sta.push(t);//完成对这个数字的读入
t=0;//t清为0
} //下面对栈内的数字进行操作
else if(s[i]=='-'){
int b,a,T;
b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
a=sta.top();sta.pop();
T=a-b;sta.push(T);
}
else if(s[i]=='+')
{
int b,a,T;
b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
a=sta.top();sta.pop();
T=a+b;sta.push(T);
}
else if(s[i]=='*'){
int b,a,T;
b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
a=sta.top();sta.pop();
T=a*b;sta.push(T);
}
else if(s[i]=='/')
{
int b,a,T;
b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
a=sta.top();sta.pop();
T=a/b;sta.push(T);
}
else if(s[i]=='@')break;
}
cout<<sta.top();
return 0;
}
T4;队列安排
一个学校里老师要将班上 NN 个同学排成一列,同学被编号为 1\sim N1∼N,他采取如下的方法:
-
先将 11 号同学安排进队列,这时队列中只有他一个人;
-
2-N2−N 号同学依次入列,编号为 ii 的同学入列方式为:老师指定编号为 ii 的同学站在编号为 1\sim(i-1)1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;
-
从队列中去掉 M(M<N)M(M<N) 个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第 11 行为一个正整数 NN,表示了有 NN 个同学。
第 2\sim N2∼N行,第 ii 行包含两个整数 k,pk,p,其中 kk 为小于 ii 的正整数,pp 为 00 或者 11。若 pp 为00,则表示将 ii 号同学插入到 kk 号同学的左边,pp 为 11 则表示插入到右边。
第 N+1N+1 行为一个正整数 MM,表示去掉的同学数目。
接下来 MM 行,每行一个正整数 xx,表示将 xx 号同学从队列中移去,如果 xx 号同学已经不在队列中则忽略这一条指令。
输出格式
11 行,包含最多 NN 个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入 #1复制
4 1 0 2 1 1 0 2 3 3
输出 #1复制
2 4 1
说明/提示
样例解释:
将同学 22 插入至同学 11 左边,此时队列为:
2 1
将同学 33 插入至同学 22 右边,此时队列为:
2 3 1
将同学 44 插入至同学 11 左边,此时队列为:
2 3 4 1
将同学 33 从队列中移出,此时队列为:
2 4 1
同学 33 已经不在队列中,忽略最后一条指令
最终队列:
2 4 1
思路:这道题是一个双链表的题目,我采用的是用数组模拟双链表的操作,然后用数组的第0号的R储存链表的开头,对于删除操作,将链表两端的R和L全部都设置为-1,对于输出到末尾元素(只将R端标记为-1,就可以结束输出循环)
#include<bits/stdc++.h>
using namespace std;
struct node{
int R,L;
}le[100005];
int n,m;
int main()
{
le[0].R=1;
le[1].L=0;le[1].R=-1;
cin>>n;
for(int i=2;i<=n;i++){
int k,p;
cin>>k>>p;
if(p)
{
le[i].L = k;
le[le[k].R].L = i;
le[i].R = le[k].R;
le[k].R = i;
}
else
{
le[i].R = k;
le[le[k].L].R = i;
le[i].L = le[k].L;
le[k].L = i;
}
//cout<<"0后面链接的数为"<<le[0].R<<endl;
}//完成插入操作
//cout<<"未删数时"<<endl;
//for(int i=1;i<=n;i++)cout<<le[i].L<<" "<<i<<' '<<le[i].R<<endl;
cin>>m;
for(int i=1;i<=m;i++)
{
int x;
cin>>x;
//for(int i=1;i<=n;i++)cout<<le[i].L<<" "<<i<<' '<<le[i].R<<endl;
if(le[x].L==-1&&le[x].R==-1)continue;
le[le[x].L].R = le[x].R;
le[le[x].R].L = le[x].L;
le[x].R = le[x].L = -1;
}
int fs=le[0].R;
while(fs != -1)
{
cout<<fs<<' ';
fs= le[fs].R;
}
return 0;
}