LCA笔记

写一写LCA问题
1.Tarjan

2.ST算法
先列一下思路8
第一步:存数据(X

//链式前向星
void add(int u,int v,int w){   
 g[cnt].v=v;    
 g[cnt].w=w;   
 g[cnt].nxt=head[u];   
 head[u]=cnt++;}

第二步:准备工作
深度dep(按照遍历顺序);
ver遍历顺序;
dp二维数组(用来存放);
first数组:节点第一次出现的时间;

//u为当前边 d是深度
void dfs(int u,int d){    //
cout<<ver[1]<<" dfa"<<endl;     
vis[u]=1;
//tot记录遍历顺序 初始值为0
ver[++tot]=u;   
dep[tot]=d;    
first[u]=tot;    
for(int i=head[u];i!=-1;i=g[i].nxt){        
int v=g[i].v;        
if(!vis[v]){            
dis[v]=dis[u]+g[i].w;            
dfs(v,d+1);  
//回溯??? ver数组中每个点要出现多次          
ver[++tot]=u;
dep[tot]=d; }}}

那么如果我们要求u与v的最近祖先,先找出它们第一次出现的时间区间,然后再在dep中找到那一段深度区间,要找是lca就是这个区间中最小的嘛

(也就是说,在从u到v的这个过程中,经过的最靠近树根的那一个节点。经过这个节点,我们可以从u到v,也可以从v回到u,即可以求v到u的最短路径 dis[u]+dis[v]-2*dis[lca(v,u)])
寻找最小值的过程我们使用rmq来解决,这样更快速
找出这个最浅深度后,我们回到一开始的ver数组中去,按这个序号,找出的那个节点,就是我们要找的lca辣!!

int RMQ(int l,int r){   
int k= 0;    
while(1<<(k+1)<=r-l+1) k++;    
int a=dp[l][k],b=dp[r-(1<<k)+1][k];    
return dep[a]<dep[b]?a:b;}
//返回 dep 在 l , r 上的最小值

int LCA(int u,int v){    
int x=first[u],y=first[v];    
if(x>y)swap(x,y);    
int res=RMQ(x,y);    
return ver[res]; } 

void ST(int n){    
for(int i=1;i<=n;i++){        
dp[i][0]=i;    
}    
for(int j=1;(1<<j)<=n;j++){        
for(int i=1;i+(1<<j)-1<=n;i++){            
int a=dp[i][j-1],b=dp[i+(1<<(j-1))][j-1];            
dp[i][j]=dep[a]<dep[b]?a:b;}}}

*插播一个rmq问题
rmq用dp思想开求一个区间上的最值(这里假设求最小值,最大值同理)
dp[i][j]表示从i位置出发,往后2^j次方个数字的区间上的最值
状态转移方程

dp[i][j]=min(dp[i][j-1],dp[i+2^(j-1) ][ j-1])
*把这个区间从中间剖成等长的两端,每段长为2^(j-1)
1.初始化操作。

void ini(int n){
 for(int i=1;i<=n;i++){
  dp[i][0]=a[i];
 }
 //1<<j就是2^j了
 for(int j=0;(1<<j)<=n;j++){
  for(int i=1;i+(1<<j)-1<=n;i++){
   dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
  }
 }
}

2.查询(l,r)上最值

int RMQ(int l,int r){
 int k=0;
 while(1<<(k+1)<=r-l+1) k++;
 //找到最大的k,覆盖 区间
 //也可以直接k=log2(r-l+1)-1; 
 return min(dp[l][k],dp[r-(1<<k)+1][k]); 
}

一个RMQ例题:Cornfields
题意就是在一个小方块里找出最大最小值 求差
本来是二位RMQ还看见一个巨强的记忆化搜索,不知道会不会超时?

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define N 255
using namespace std;
int dp1[N][N][8][8];
int dp2[N][N][8][8]; 
int a[N][N];
int n;
int minn(int a,int b,int c,int d){
	int m=min(a,b);
	int n=min(c,d);
	return min(m,n);
}
int maxn(int a,int b,int c,int d){
	int m=max(a,b);
	int n=max(c,d);
	return max(m,n);
}
//这里的dp[r][c][kn][km]指的是以r,c为左上角,2^kn行,2^km列的矩阵中的最值
void st(int n,int m){
	int i,j,r,c;
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			dp1[i][j][0][0]=dp2[i][j][0][0]=a[i][j];
		} 
	}
	int kn=(int)(log(double(n))/log(2.0));
	int km=(int)(log(double(m))/log(2.0));
	for(i=0;i<=kn;i++){
		for(j=0;j<=km;j++){
			if(!i&&!j)continue; 
			for(r=1;r+(1<<i)-1<=n;r++){
				for(c=1;c+(1<<j)-1<=m;c++){
					if(!i){
						dp1[r][c][i][j]=min(dp1[r][c][i][j-1],dp1[r][c+(1<<(j-1))][i][j-1]);
						dp2[r][c][i][j]=max(dp2[r][c][i][j-1],dp2[r][c+(1<<(j-1))][i][j-1]);
					}
					else{
						dp1[r][c][i][j]=min(dp1[r][c][i-1][j],dp1[r+(1<<(i-1))][c][i-1][j]);
						dp2[r][c][i][j]=max(dp2[r][c][i-1][j],dp2[r+(1<<(i-1))][c][i-1][j]);
					}
				}
			}
		}
	}
 } 
int RMQ(int x,int y,int x1,int y1){
	int l=(int)(log(double(x1-x+1))/log(2.0));
	int k=(int)(log(double(y1-y+1))/log(2.0));
	return minn(dp1[x][y][l][k],dp1[x1-(1<<l)+1][y][l][k],
				dp1[x][y1-(1<<k)+1][l][k],dp1[x1-(1<<l)+1][y1-(1<<k)+1][l][k]);
	
}
int RMQ2(int x,int y,int x1,int y1){
	int l=(int)(log(double(x1-x+1))/log(2.0));
	int k=(int)(log(double(y1-y+1))/log(2.0));
	return maxn(dp2[x][y][l][k],dp2[x][y1-(1<<l)+1][l][k],
				dp2[x1-(1<<l)+1][y][l][k],dp2[x1-(1<<l)+1][y1-(1<<k)+1][l][k]);
}

int main()
{int n, b, k, i, j;
cin >> n >> b >> k;
for (i = 1; i <= n; i++)        
for (j = 1; j <= n; j++){
scanf("%d", &a[i][j]);}
st(n,n);
int u, l;    
for (i = 0; i < k; i++)
    {
scanf("%d%d", &u, &l);
    cout<<RMQ2(u,l,u+b-1,l+b-1)-RMQ(u,l,u+b-1,l+b-1)<<endl;
}
return 0;
}
法二
 int c[255][255];//记忆数组
  int max=0,min=999999999;
  if(!c[x][y]){
   for(int l=x;l<=x+b-1;l++){
   for(int c=y;c<=y+b-1;c++){
    if(a[l][c]<min) min = a[l][c];
    if(a[l][c]>max) max = a[l][c];
   } }
   c[x][y]=max-min;}
  cout<<c[x][y]<<endl;
发布了24 篇原创文章 · 获赞 2 · 访问量 973

猜你喜欢

转载自blog.csdn.net/weixin_43521836/article/details/88757441
lca