2020.10.2 清北学堂 J2综合强化营 D2 数据结构笔记

数据结构

(1).基础知识
需要掌握:数组,链表,队列,栈,堆
((1)) 队列:FIFO(先进先出)
((2)) 栈:FILO(先进后出)

(2).堆

浅谈堆

((1)).实现:二叉树

二叉树最简单的实现:一维数组
二叉树编号法:设当前的节点编号为i,则其左儿子(2i) ,右儿子(2i+1)

((2)).分类

大根堆:一个节点一定比它的两个儿子的权值大
(所以求最大值直接返回根节点)

小根堆:一个节点一定比它的两个儿子的权值小
(所以求最小值直接返回根节点)

((3)).基本操作

  • 返回最值 ((max or min))
  • 删除(堆顶元素)任意元素
  • 插入一个元素
strcut Heap{
	int n;	//有n个数
	int a[100010];	//这n个数存在了a[1~n];

	inline int top{	//求最大值
		return a[1];	
	}
	
	inline void insert(int x){	//插入
		a[++n]=x;	//放到最后
		int p=n;
		while(p>1 && a[p]>a[p/2]) swap(a[p],a[p/2]),p/=2;
		//p>1 保证不是根节点
		//a[p]>a[p/2] -> 如果当前节点比其父节点值大,不满足大根堆的要求,交换
		//直至合法为止	
	}

	inline void delete(int q){
		swap(a[q],a[n]);n--;	//删除a[q]
		int p=1;
		while(p*2<=n){	//左儿子存在
			int pp=2*p;	//左儿子
			if(pp+1<n &&a[pp+1]>a[pp]) pp++;
			//如果右儿子也存在,且右儿子值比左儿子值大,指向右儿子
			//如否,指向左儿子
			//不管指向谁,都是较大的那个
			if(a[p]<a[pp]){
				swap(a[p],a[pp]);
				p=pp;
			}
		}
	}
};

(3).ST表

浅谈ST表

(ST)表是一种用于解决 (RMQ) (Range Minimum/Maximum Query,即区间最值查询)问题的算法

以最小值为例:

表示:令(f[i][j])表示从 (i) 开始 (2^j) 个数的最小值
则显然 (f[i][0]=a[i]);

转移:(f[i][j]=min(f[i][j-1],f[i+2^{j-1)}][j-1]));
解释:根据 (2^j=2^{j-1} + 2^{j-1})
(f[i][j-1]) -> 先从 (i)(2^{j-1}) 个数
(f[i+2^{j-1}][j-1]) -> 现在的起始位置为上次走完 (2^{j-1}) 后的位置
故为(i+2^{j-1}),再走(2^{j-1}),故(f[i+2^{j-1}][j-1])

int main(){
	cin>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=0;(1<<i)<=n;i++)
		for(int j=(1<<i);j<(1<<(i+1));j++)	//j从2^i~2^(i+1)
			use[j]=i;	//use[i] 表示用两个长度为use[i]的段盖住长度为i的段

	for(int i=1;i<=n;i++) f[i][0]=a[i];	//初始化

	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;(1<<i)<=n;i++)
			f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	//1<<j表示2^j,指1左移j位,得到的结果在十进制下为2^j

	for(int i=1;i<=m;i++){
		int l,r;
		cin>>l>>r;	//左右端点
		int len=r-l+1;	//[l,r]长度
		int j=use[len];	
		cout<<min(f[l][j],f[r-(1<<j)+1][j]);
	}
}

(Practice):

(Problem 1):给你 (N) 个数,求平均值最大的子区间
(Solution Problem 1): 因为(从最大值开始)每加进来一个数平均值都会减小,所以其实答案就是数组里最大的那个数。

(Problem 2):给你 (N) 个数,求(min(a_i,a_{i+1},...a_j) * |i-j|)的最大值 ((N<=10^5))

(Problem 3):给定 (N) 个点,这 (N) 个点与 (N-1) 条边组成一个树。
(M)次询问,每次询问给定(p1,p2)两点,问这两点之间的路径上有没有三个点,他们的点权可以构成一个三角形的三边。对于每一次询问,输出"YES"或"NO"

(Problem 4):
现有一个 (N*N) 的矩阵,其中有 (M) 个特殊点。
两个点的距离定义为它们的曼哈顿距离。
任意一个点的权值 指它到达每个特殊点的距离的最小值。
((1,1)) 走到 ((n,n)),求经过的权值的最小值最大是多少

(Solution Problem 4):“最小值最大” -> 二分

(4).单调队列

有单调性的队列,即单调递减或单调递增的队列。

浅谈单调队列
struct Monotone_queue{
	int q[100010];	//存队列元素
	int head=1;tail=0;	//队头,队尾
	void pop{      //Detele
		head++;	
	}
	void push(int x){      //Add
		while(head<tail && q[tail]>x) tail--;
		//队列尾部的数比插入的数大,插入后无法保证单调性
		//tail-- -> 相当于实现把队列尾部数弹出,直到合法
		q[++tail]=x;	
	}
}

(5).并查集

浅谈并查集
inline int find(int p){      
	if(p=fa[p]) return p;
	//return fa[p]=find(fa[p]);
	int x=find(fa[p]);
	fa[p]=x;
	return x;		
}
inline void merge(int x,int y){
	x=find(x);
	y=find(y);
	if(x==y) return;
	fa[x]=y;
}
/*inline void merge(int x,int y){
      fa[find(x)]=find(y); 
}
*/
原文地址:https://www.cnblogs.com/-pwl/p/13763100.html