数据结构day1


DAY1


RMQ

RMQ即为Range Maximun/Minimum Query,范围内的区间最大/小值查询,可用线段树,树状数组,ST表等方法解决

倍增

ST表

实现ST表算法是一种倍增的方式
如下专门介绍

快速幂

预处理出 a , a 2 , a 4 , a 8 . . . a,a^2,a^4,a^8... a,a2,a4,a8...
考虑二进制,将 a b a^b ab转换成一些数的乘积
显然,若 f [ i ] = a 2 i f[i]=a^{2^i} f[i]=a2i,则 f [ i ] = f [ i − 1 ] ∗ f [ i − 1 ] f[i]=f[i-1]*f[i-1] f[i]=f[i1]f[i1]

int quick_pow(int a,int b){
	int ans=1,p=a;
	for(int i=b;i;i>>=1){
		if(i&1) ans=ans*p%mod;
		p=p*p%mod;
	}
	return ans;
}

LCA

LCA即Lowest Common Ancestor,树上两个节点的最近公共祖先
状态:数组an[i][j]表示节点i的第 2 j 2^j 2j级祖先,
转移: a n [ i ] [ j ] = = { a n [ a n [ i ] [ j − 1 ] [ j − 1 ]   j > 0 f a [ i ]   j = 0 an[i][j]==\left\{ \begin{aligned} an[an[i][j-1][j-1]&&\ j>0\\ fa[i]&&\ j=0 \end{aligned} \right. an[i][j]=={an[an[i][j1][j1]fa[i] j>0 j=0
若两个节点的深度相同,可倍增;若不同,可将深度较大的点调到深度较小的点,然后同上

void dfs(int x,int fa){
	an[x][0]=fa,dep[x]=dep[fa]+1;
	for(int i=1;i<=size;i++) an[x][i]=an[an[x][i-1]][i-1];
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i];
		if(y==fa) continue;
		dfs(y,x);
	}
}
int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=0;i<=size;i++)
		if((dep[x]-dep[y])&(1<<i)) x=an[x][i];
	if(x==y) return x;
	for(int i=size;i>=0;i--){
		if(an[x][i]!=an[y][i]){
			x=an[x][i];
			y=an[y][i];
		}
	}
	return an[x][0];
}

ST表(sparse table)

主要运用倍增+dp的思想
状态:设一个二维数组f,表示从i开始取 2 j 2^j 2j个数的最小值,如不足则全取。
转移:
f [ i ] [ j ] = = { m i n ( f [ i ] [ j − 1 ] , f [ i + 2 j − 1 ] [ j − 1 ]   j > 0 且 i + 2 j − 1 < = n f [ i ] [ j − 1 ]   j > 0 且 i + 2 j − 1 > n a [ i ]   j = 0 f[i][j]==\left\{ \begin{aligned} min(f[i][j-1],f[i+2^{j-1}][j-1] &&\ j>0且i+2^{j-1}<=n \\ f[i][j-1]&&\ j>0且i+2^{j-1}>n\\ a[i]&&\ j=0 \end{aligned} \right. f[i][j]==min(f[i][j1],f[i+2j1][j1]f[i][j1]a[i] j>0i+2j1<=n j>0i+2j1>n j=0
j从小到大枚举推出f数组
然后对于询问(l,r),设 x = l o g 2 ( r − l + 1 ) x=log_2(r-l+1) x=log2(rl+1)
答案为 m i n ( f [ i ] [ x ] , f [ r − 2 x + 1 ] [ x ] ) min(f[i][x],f[r-2^x+1][x]) min(f[i][x],f[r2x+1][x])

基于ST表的倍增

可以在欧拉序时将深度记录下来
任意两点节点的LCA即为两个节点所在的区间的深度的最小值
就可用ST表维护

二维ST表

就是在ST表的基础上加了一维
状态: f [ x ] [ y ] [ a ] [ b ] f[x][y][a][b] f[x][y][a][b]表示在横坐标为 [ x , m i n ( n , x + 2 a − 1 ) ] [x,min(n,x+2^a-1)] [x,min(n,x+2a1)],纵坐标为 [ y , m i n ( m , y + 2 b − 1 ] [y,min(m,y+2^b-1] [y,min(m,y+2b1]的矩形内的最大值
转移:
f [ x ] [ y ] [ a ] [ b ] = = { m i n ( f [ x ] [ y ] [ a − 1 ] [ b ] , f [ x + 2 a − 1 ] [ y ] [ a − 1 ] [ b ] )   a > 0 且 x + 2 a − 1 < = n f [ x ] [ y ] [ a ] [ b − 1 ]   x + 2 ( a − 1 ) > n 且 a > 0 m i n ( f [ x ] [ y ] [ a ] [ b − 1 ] , f [ x ] [ y + 2 b − 1 ] [ a ] [ b − 1 ] )   b > 0 且 y + 2 b − 1 < = n f [ x ] [ y ] [ a − 1 ] [ b ]   y + 2 ( b − 1 ) > n 且 b > 0 v a l [ x ] [ y ]   a = b 且 b = 0 f[x][y][a][b]==\left\{ \begin{aligned} min(f[x][y][a-1][b],f[x+2^{a-1}][y][a-1][b])&&\ a>0且x+2^{a-1}<=n \\ f[x][y][a][b-1]&&\ x+2^(a-1)>n且a>0\\ min(f[x][y][a][b-1],f[x][y+2^{b-1}][a][b-1])&&\ b>0且y+2^{b-1}<=n \\ f[x][y][a-1][b]&&\ y+2^(b-1)>n且b>0\\ val[x][y]&&\ a=b且b=0 \end{aligned} \right. f[x][y][a][b]==min(f[x][y][a1][b],f[x+2a1][y][a1][b])f[x][y][a][b1]min(f[x][y][a][b1],f[x][y+2b1][a][b1])f[x][y][a1][b]val[x][y] a>0x+2a1<=n x+2(a1)>na>0 b>0y+2b1<=n y+2(b1)>nb>0 a=bb=0
对于每组询问,设 k x = l o g 2 ( x r − x l + 1 ) , k y = l o g 2 ( y r − y l + 1 ) kx=log_2(xr-xl+1),ky=log_2(yr-yl+1) kx=log2(xrxl+1),ky=log2(yryl+1)
则答案为: m a x ( f [ x l ] [ y l ] [ k x ] [ k y ] , f [ x r − 2 k x + 1 , f [ x l ] [ y r − 2 k y + 1 ] [ k x ] [ k y ] , f [ x r − 2 k x + 1 ] [ y r − 2 k y + 1 ] [ k x ] [ k y ] ) max(f[xl][yl][kx][ky],f[xr-2^{kx}+1,f[xl][yr-2^{ky}+1][kx][ky],f[xr-2^{kx}+1][yr-2^{ky}+1][kx][ky]) max(f[xl][yl][kx][ky],f[xr2kx+1,f[xl][yr2ky+1][kx][ky],f[xr2kx+1][yr2ky+1][kx][ky])

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值