STL

STL

0. 简介

STL 即标准模板库(Standard Template Library),是 C++ 标准库的一部分,里面包含了一些模板化的通用的数据结构和算法。由于其模板化的特点,它能够兼容自定义的数据类型,避免大量的造轮子工作。NOI 和 ICPC 赛事都支持 STL 库的使用,因此合理利用 STL 可以避免编写无用算法,并且充分利用编译器对模板库优化提高效率。

题目来源

1.Dynamic Arrays and Lists

(1).Vector

题意

维护动态数组 \(A\),支持以下三种操作:

  • push_back(x): 在 \(A\) 的末尾加入元素 \(x\)
  • random_access(p): 查询元素 \(A_p\)
  • pop_back(): 删除 \(A\) 的最后一个元素

简介

vector 是 STL 提供的一种 内存连续,长度可变 的动态数组。

虽说动态数组,但 vector 的底层仍是定长数组。当数组大小不足时,vector 会倍增的申请、分配更多连续的空间。

定义

vector<int>h; 定义一个数据类型为 intvector h

需要头文件 #include<vector>

函数

  • push_back(int value) 在 vector 的末尾加入元素 value,均摊时间复杂度 \(O(1)\),最坏复杂度为 \(O(n)\)(倍增申请空间)。
  • operator[] 访问 vector 中的某一元素,用法与普通数组相同,时间复杂度 \(O(1)\)
  • pop_back() 删除 vector 的最后一个元素,时间复杂度 \(O(1)\)

代码

int n;
vector<int>h;
int main()
{
	n=re();
	for(int i=1;i<=n;i++)
	{
		int op=re();
		if(op==0)h.push_back(re());
		if(op==1)wr(h[re()]),putchar('\n');
		if(op==2)h.pop_back();
	}
	return 0;
}

(2).Deque

题意

维护动态数组 \(A\),支持以下三种操作:

  • push(d,x): 如果 d=0,在 \(A\) 的开头加入元素 \(x\);如果 d=1,在 \(A\) 的末尾加入元素 \(x\)
  • random_access(p): 查询元素 \(A_p\)
  • pop(): 如果 d=0,删除 \(A\) 的第一个元素;如果 d=1,删除 \(A\) 的最后一个元素

简介

deque 是 STL 提供的一种双端队列。

基本操作与 vector 相似。

定义

deque<int>h; 定义一个数据类型为 intdeque h

需要头文件 #include<deque>

函数

  • push_front(int value) 在 deque 的开头加入元素 value,时间复杂度 \(O(1)\)
  • push_back(int value) 在 deque 的末尾加入元素 value,时间复杂度 \(O(1)\)
  • operator[] 访问 deque 中的某一元素,用法与普通数组相同,时间复杂度 \(O(1)\)
  • pop_front() 删除 deque 的第一个元素,时间复杂度 \(O(1)\)
  • pop_back() 删除 deque 的最后一个元素,时间复杂度 \(O(1)\)

代码

int n;
deque<int>h;
int main()
{
	n=re();
	for(int i=1;i<=n;i++)
	{
		int op=re();
		if(op==0)
		{
			int pd=re(),k=re();
			if(pd)h.push_back(k);
			else h.push_front(k);
		}
		if(op==1)wr(h[re()]),putchar('\n');
		if(op==2)
		{
			int pd=re();
			if(pd)h.pop_back();
			else h.pop_front();
		}
	}
	return 0;
}

(3).List

题意

维护动态链表 \(L\),支持以下三种操作:

  • insert(x): 在 \(L\) 的光标所指元素之前插入元素 \(x\),随后光标指向元素 \(x\)
  • move(d): 光标向后移动 \(d\) 个单位
  • erase(): 删除 \(L\) 的光标所指的元素,随后光标指向下一个元素

最开始 \(L\) 为空,仅含有一个特殊的元素 END,光标指向 END。

简介

list 是 STL 提供的一种双向链表。

基本操作与 deque 相似。

定义

list<int>h; 定义一个数据类型为 intlist h

需要头文件 #include<list>

函数

  • insert(list<int>::iterator IT,int value) 在 list 的 IT 位置插入元素 value,时间复杂度 \(O(1)\)
  • erase(list<int>::iterator IT) 删除 list 的 IT 位置的元素,时间复杂度 \(O(1)\);并返回一个迭代器,指向下一个元素。
  • begin() 返回一个迭代器,指向 list 的第一个元素。
  • end() 返回一个迭代器,指向 list 的最后一个元素的后一个位置。

迭代器

由题意可得,迭代器(即光标)最初指向 list 的末尾:

list<int>::iterator IT=h.end();

list 重载了 ++--。以自增为例,对于数来说,就是简单的 +1;而对于迭代器而言,则是移动到下一个位置。

那么 move 操作就只需要将迭代器自增、自减即可。

代码

int n;
list<int>h;
int main()
{
	n=re();
	list<int>::iterator IT=h.end();
	for(int i=1;i<=n;i++)
	{
		int op=re();
		if(op==0)h.insert(IT,re()),IT--;
		if(op==1)
		{
			int m=re();
			if(m>0)while(m--)IT++;
			else while(m++)IT--;
		}
		if(op==2&&h.size())IT=h.erase(IT);
	}
	for(IT=h.begin();IT!=h.end();IT++)
		wr(*IT),putchar('\n');
	return 0;
}

(4).Vector II

题意

维护 n 个动态数组 \(A_i\),支持以下三种操作:

  • push_back(t,x): 在 \(A_t\) 的末尾加入元素 \(x\)
  • dump(t): 查询 \(A_t\) 的所有元素
  • clear(t): 清空 \(A_t\)

定义

vector<int>h[inf]; 定义 inf 个数据类型为 intvector,其中第 i 个为 h[i]

函数

  • push_back(int value) 同上。
  • size() 返回一个整数,为当前 vector 中元素个数。
  • clear() 清空整个 vector。

代码

const int inf=1e3+7;
int n,m;
vector<int>h[inf];
int main()
{
	n=re();m=re();
	for(int i=1;i<=m;i++)
	{
		int op=re(),x=re();
		if(op==0)h[x].push_back(re());
		if(op==1)
		{
			int len=h[x].size();
			if(len)
			{
				for(int j=0;j<len-1;j++)
					wr(h[x][j]),putchar(' ');
				wr(h[x][len-1]);
			}putchar('\n');
		}
		if(op==2)h[x].clear();
	}
	return 0;
}

2.Basic Data Structures

(1).Stack

题意

维护 n 个栈 \(S_i\),支持以下三种操作:

  • push(t,x): 在栈 \(S_t\) 的顶部加入元素 \(x\)
  • top(t): 查询栈 \(S_t\) 的栈顶元素
  • pop(t): 弹出栈 \(S_t\) 的栈顶元素

简介

stack 是 STL 提供的一种栈。

其底层容器是 deque。

定义

stack<int>h[inf]; 定义 inf 个数据类型为 intstack,其中第 i 个为 h[i]

需要头文件 #include<stack>

函数

  • push(int value) 在 stack 的顶部加入元素 value,时间复杂度 \(O(1)\)
  • top() 返回一个整数,为 stack 的栈顶元素,时间复杂度 \(O(1)\)
  • pop() 弹出 stack 的栈顶元素,时间复杂度 \(O(1)\)

代码

const int inf=1e3+7;
int n,m;
stack<int>h[inf];
int main()
{
	n=re();m=re();
	for(int i=1;i<=m;i++)
	{
		int op=re(),x=re();
		if(op==0)h[x].push(re());
		if(op==1&&h[x].size())wr(h[x].top()),putchar('\n');
		if(op==2&&h[x].size())h[x].pop();
	}
	return 0;
}

(2).Queue

题意

维护 n 个队列 \(Q_i\),支持以下三种操作:

  • enqueue(t,x): 在队列 \(Q_t\) 的队尾加入元素 \(x\)
  • front(t): 查询队列 \(Q_t\) 的队首元素
  • dequeue(t): 弹出队列 \(Q_t\) 的队首元素

简介

queue 是 STL 提供的一种队列。

其底层容器是 deque。

定义

queue<int>h[inf]; 定义 inf 个数据类型为 intqueue,其中第 i 个为 h[i]

需要头文件 #include<queue>

函数

  • push(int value) 在 queue 的队尾加入元素 value,时间复杂度 \(O(1)\)
  • front() 返回一个整数,为 queue 的队首元素,时间复杂度 \(O(1)\)
  • pop() 弹出 queue 的队首元素,时间复杂度 \(O(1)\)

代码

const int inf=1e3+7;
int n,m;
queue<int>h[inf];
int main()
{
	n=re();m=re();
	for(int i=1;i<=m;i++)
	{
		int op=re(),x=re();
		if(op==0)h[x].push(re());
		if(op==1&&h[x].size())wr(h[x].front()),putchar('\n');
		if(op==2&&h[x].size())h[x].pop();
	}
	return 0;
}

(3).Priority Queue

题意

维护 n 个优先队列 \(Q_i\),支持以下三种操作:

  • insert(t,x): 在优先队列 \(Q_t\) 中插入元素 \(x\)
  • get_max(t): 查询优先队列 \(Q_t\) 中的最大值
  • delete_max(t): 弹出优先队列 \(Q_t\) 中的最大值

简介

priority_queue 是 STL 所提供的堆。

其底层容器为 vector。

定义

priority_queue<int>h[inf]; 定义 inf 个数据类型为 intpriority_queue,其中第 i 个为 h[i]

需要头文件 #include<queue>

函数

  • push(int value) 在 priority_queue 中插入元素 value,时间复杂度 \(O(\log n)\)
  • top() 返回一个整数,为 priority_queue 中的最大值,时间复杂度 \(O(1)\)
  • pop() 弹出 priority_queue 中的最大值,时间复杂度 \(O(\log n)\)

拓展

STL 默认的 priority_queue 是大根堆,如果要定义小根堆可以尝试以下方法:

  • STL 嵌套

利用 greater 和 less 改变优先级。

需要头文件 #include<functional>

对于普通的数组排序(sort),默认排序方式为从小到大,less 表示从小到大排序,greater 表示从大到小排序。

而对于优先队列,默认排序方式为从大到小,less 表示从大到小排序,greater 表示从小到大排序。

使用方法:

数组(以 vector 为例)

sort(a.begin(),a.end(),less<int>());//小->大
sort(a.begin(),a.end(),greater<int>());//大->小

优先队列

priority_queue<int,vector<int>,less<int> >h;//大根堆
priority_queue<int,vector<int>,greater<int> >h;//小根堆
  • 重载运算符

用一个结构体重载 <,然后存入 priorit_queue

struct data{
	int a;
	bool operator <(const data &b)const
	{
		return a>b.a;
	}
};
priority_queue<data>h;

代码

const int inf=1e3+7;
int n,m;
priority_queue<int>h[inf];
int main()
{
	n=re();m=re();
	for(int i=1;i<=m;i++)
	{
		int op=re(),x=re();
		if(op==0)h[x].push(re());
		if(op==1&&h[x].size())wr(h[x].top()),putchar('\n');
		if(op==2&&h[x].size())h[x].pop();
	}
	return 0;
}

(4).Splice

题意

维护 n 个链表 \(L_i\),支持以下三种操作:

  • insert(t,x): 在 \(L_t\) 的末尾加入元素 \(x\)
  • dump(t): 查询 \(L_t\) 的所有元素
  • splice(s,t): 将 \(L_s\) 的所有元素插入到 \(L_t\) 的末尾,并清空 \(L_s\)

函数

  • push_back(int value) 同上。
  • splice(list<int>::iterator IT,list L)\(L\) 转移到 IT 的位置。

拓展

  • splice(list<int>::iterator IT1,list,list<int>::iterator IT2) 将 list 的 IT2 位置上的元素转移到 IT1 的位置上。
  • splice(list<int>::iterator IT,list,list<int>::iterator begin,list<int>::iterator end) 将 list 的 [begin,end) 位置的元素转移到 IT 的位置。

代码

const int inf=1e3+7;
int n,m;
list<int>h[inf];
int main()
{
	n=re();m=re();
	for(int i=1;i<=m;i++)
	{
		int op=re(),x=re();
		if(op==0)h[x].push_back(re());
		if(op==1)
		{
			list<int>::iterator IT=h[x].begin(),end_=--h[x].end();
			if(h[x].size())
			{
				while(IT!=end_)
				{
					wr(*IT),putchar(' ');
					IT++;
				}
				wr(*end_);
			}putchar('\n');
		}
		if(op==2)
		{
			int y=re();
			h[y].splice(h[y].end(),h[x]);
		}
	}
	return 0;
}

3.Basic Operations

(1).Min-Max

题意

输入三个整数 \(a,b,c\),输出 \(a,b,c\) 中的最小值和最大值。

函数

  • min(int x,int y) 返回一个整数,即 \(a,b\) 中较小的数。
  • max(int x,int y) 返回一个整数,即 \(a,b\) 中较大的数。

需要头文件 #include<algorithm>

代码

int a,b,c;
int main()
{
	a=re();b=re();c=re();
	wr(min(min(a,b),c));putchar(' ');
	wr(max(max(a,b),c));putchar('\n');
	return 0;
}

(2).Min-Max Element

题意

维护给定的数组 \(A\),支持以下两种操作:

  • min(b,e) 查询 \(A_{b},A_{b+1},\cdots,A_{e-1}\) 中的最小值。
  • max(b,e) 查询 \(A_{b},A_{b+1},\cdots,A_{e-1}\) 中的最大值。

函数

  • min_element(iterator begin,iterator end) 返回一个迭代器,即 [begin,end) 中的最小值的位置。
  • max_element(iterator begin,iterator end) 返回一个迭代器,即 [begin,end) 中的最大值的位置。

需要头文件 #include<algorithm>

代码

const int inf=1e3+7;
int n,m,a[inf];
int main()
{
	n=re();
	for(int i=0;i<n;i++)
		a[i]=re();
	m=re();
	for(int i=1;i<=m;i++)
	{
		int op=re(),sta_=re(),end_=re();
		if(op)wr(*max_element(a+sta_,a+end_)),putchar('\n');
		else wr(*min_element(a+sta_,a+end_)),putchar('\n');
	}
	return 0;
}

(3).Count

题意

维护给定的数组 \(A\),支持以下操作:

  • count(b,e,k) 查询 \(k\)\(A_{b},A_{b+1},\cdots,A_{e-1}\) 中出现了几次。

函数

  • count(iterator begin,iterator end,int value) 返回一个数,即 [begin,end) 中 value 出现的次数。

需要头文件 #include<algorithm>

代码

const int inf=1e3+7;
int n,m,a[inf];
int main()
{
	n=re();
	for(int i=0;i<n;i++)
		a[i]=re();
	m=re();
	for(int i=1;i<=m;i++)
	{
		int sta_=re(),end_=re(),k=re();
		wr(count(a+sta_,a+end_,k));putchar('\n');
	}
	return 0;
}

(4).Lexicographical Comparison

题意

比较给定的数组 \(A,B\) 的字典序大小。

函数

  • lexicographical_compare(iterator begin1,iterator end1,iterator begin2,iterator end2) 返回一个布尔,即 [begin1,end1) 的字典序是否小于 [begin2,end2)。

需要头文件 #include<algorithm>

代码

const int inf=1e3+7;
int n,m,a[inf],b[inf];
int main()
{
	n=re();
	for(int i=0;i<n;i++)
		a[i]=re();
	m=re();
	for(int i=0;i<m;i++)
		b[i]=re();
	wr(lexicographical_compare(a,a+n,b,b+m));
	putchar('\n');
	return 0;
}

4.Basic Modifications

(1).Reverse

题意

维护给定的数组 \(A\),支持以下操作:

  • reverse(b,e) 翻转区间 \(A_b,A_{b+1},\cdots,A_{e-1}\)

函数

  • reverse(iterator begin,iterator end) 翻转区间 [begin,end)。

需要头文件 #include<algorithm>

代码

const int inf=1e3+7;
int n,m,a[inf];
int main()
{
	n=re();
	for(int i=0;i<n;i++)
		a[i]=re();
	m=re();
	for(int i=1;i<=m;i++)
	{
		int sta_=re(),end_=re();
		reverse(a+sta_,a+end_);
	}
	for(int i=0;i<n-1;i++)
		wr(a[i]),putchar(' ');
	wr(a[n-1]),putchar('\n');
	return 0;
}

(2).Rotate

题意

维护给定的数组 \(A\),支持以下操作:

  • rotate(b,m,e) 对于整数 k(\(b\le k<e\)),将 \(A_{k}\) 移动到 \(A_{(k+(e-m))\bmod(e-b)}\)

函数

  • rotate(iterator begin,iterator mid,iterator end) 将区间 [begin,mid) 转移到区间 [mid,end) 之后。

需要头文件 #include<algorithm>

至于为什么叫 rotate,将整个区间拼接成环试试?

代码

const int inf=1e3+7;
int n,m,a[inf];
int main()
{
	n=re();
	for(int i=0;i<n;i++)
		a[i]=re();
	m=re();
	for(int i=1;i<=m;i++)
	{
		int sta_=re(),mid_=re(),end_=re();
		rotate(a+sta_,a+mid_,a+end_);
	}
	for(int i=0;i<n-1;i++)
		wr(a[i]),putchar(' ');
	wr(a[n-1]),putchar('\n');
	return 0;
}

(3).Swap

题意

维护给定的数组 \(A\),支持以下操作:

  • swap_range(b,e,t) 对于整数 k(\(0\le k<(e-b)\)),交换 \(A_{b+k}\)\(A_{t+k}\)

函数

  • swap_range(iterator begin1,iterator end1,iterator begin2) 交换区间 [begin1,end1) 和区间 [begin2,begin2+end1-begin1)。

需要头文件 #include<algorithm>

拓展

swap(int a,int b) 用于交换两个整数 \(a,b\) 的值。

swap(iterator a,iterator b) 用于交换两个迭代器。

swap(container a,container b) 用于交换两个容器。

代码

const int inf=1e3+7;
int n,m,a[inf];
int main()
{
	n=re();
	for(int i=0;i<n;i++)
		a[i]=re();
	m=re();
	for(int i=1;i<=m;i++)
	{
		int sta1=re(),end1=re(),sta2=re();
		swap_ranges(a+sta1,a+end1,a+sta2);
	}
	for(int i=0;i<n-1;i++)
		wr(a[i]),putchar(' ');
	wr(a[n-1]),putchar('\n');
	return 0;
}

(4).Unique

题意

对于给定的非严格单调的数组 \(A\),删除一些元素,使得 \(A\) 中包含的元素仅剩一个。

函数

  • unique(iterator begin,iterator end) 将区间 [begin,end) 中相邻且相同的元素移动到区间末尾;并返回一个迭代器,指向压缩后的序列末尾。

需要头文件 #include<algorithm>

代码

const int inf=1e5+7;
int n,a[inf];
int main()
{
	n=re();
	for(int i=0;i<n;i++)
		a[i]=re();
	n=unique(a,a+n)-a;
	for(int i=0;i<n-1;i++)
		wr(a[i]),putchar(' ');
	wr(a[n-1]),putchar('\n');
	return 0;
}

5.Permutation

7.Set

8.Dictionary

9.Set Operation

10.Bitset I

11.Bitset II

posted @ 2022-06-12 21:30  Zvelig1205  阅读(166)  评论(0)    收藏  举报