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); 
}
*/
posted @ 2020-10-03 12:58  _pwl  阅读(240)  评论(2编辑  收藏  举报
1 2 3
4