题目链接
#include <bits/stdc++.h>
using namespace std;
int n, m;
list<int> lt;
/*list是stl自带的双向列表
* 它不支持随机查询,但可以快速地插入和删除数据
* 这道题正好考察了链表重要的三个基本操作:
* 插入,删除,浏览
* 这道题很适合熟悉list的用法
*/
int main()
{
cin >> n;
list<int>::iterator iter;//list的迭代器,存放的是地址
lt.push_back(1);//第一位同学进入链表
for ( int i = 2 ; i <= n ; i++ )
{
int x, y;
cin >> x >> y;//插入的位置和方向
if ( y )//往右边插入
{
//list的插入是往目标的前方也就是左侧插入
//因此我们若需要向k号元素的右侧插入元素,需要在k+1号元素使用insert
for ( iter = lt.begin() ; iter != lt.end() && *iter != x ; iter++ );//从链表开头遍历编号为x的元素
//list的++被重载过,相当于迭代器向后迭代
lt.insert(++iter, i);
}
else//向左边插入
{
for ( iter = lt.begin() ; iter != lt.end() && *iter != x ; iter++ );
lt.insert(iter, i);
}
}
cin >> m;
while ( m-- )//大清洗
{
int x;
cin >> x;
for ( iter = lt.begin() ; iter != lt.end() && *iter != x ; iter++ );//依旧通过遍历找到目标元素
if ( iter != lt.end())//找到了才能删
lt.erase(iter);
}
for ( iter = lt.begin() ; iter != lt.end() ; iter++ )//遍历输出链表
cout << *iter << ' ';
return 0;
}
既学到了新的知识,又过了题目,大家都快快乐乐的.
但学了新东西有亿点点飘了,就…
掐指一算,程序复杂度O(m*n)
看一眼数据范围,mn都是106,那么最坏情况下大概的确是会爆掉的orz
论写题之前先算一下时间复杂度的重要性.jpg
于是牵扯出来对list的优化:
list本身是没法随机读取,但list的迭代器就是指针,那把迭代器按下标存起来不就方便找了吗?
优化ing
#include <bits/stdc++.h>
using namespace std;
using Iter = list<int>::iterator;
/*又是船新的知识,还有这种定义的操作?
* 这属于是起别名的操作,和typedef功能有点像,但可以做的更多
* 比如typedef就不能给这个模板类取别名
*/
#define N 1000005
int n, m;
list<int> lt;
Iter elt[N];
int main()
{
cin >> n;
Iter iter;//list的迭代器,存放的是地址
lt.push_back(1);//第一位同学进入链表
elt[1] = lt.begin();//第一位同学的地址
for ( int i = 2 ; i <= n ; i++ )
{
int x, y;
cin >> x >> y;//插入的位置和方向
if ( y )//往右边插入
{
//既然存了地址就不需要这么麻烦了
iter = elt[x];
lt.insert(++iter, i);
elt[i] = --iter;//存一下地址
//得益于stl类型左闭右开的特点,即使是在末尾这么干也不会出现越界操作
}
else//向左边插入
{
iter = elt[x];
lt.insert(iter, i);
elt[i] = --iter;
}
}
cin >> m;
while ( m-- )//大清洗
{
int x;
cin >> x;
//也不需要遍历了,有就可以删
if ( elt[x] != lt.end())
lt.erase(elt[x]);
elt[x] = lt.end();
}
for ( iter = lt.begin() ; iter != lt.end() ; iter++ )//遍历输出链表
cout << *iter << ' ';
return 0;
}
完美~