1.区间最值st表
st表的修改复杂度,查询复杂度,适合解决修改很少,询问很多的区间最值问题
其中,st表建表过程如下,记表示从i个位置开始长度为的区间最值,则,即
void build(){
for(int i=1;i<=30;i++){//2的阶
for(int j=1;j<=n;j++)
{
f[j][i][0]=f[j][i-1][0];//上一个长度2^i-1
f[j][i][1]=f[j][i-1][1];
if(j+k<=n){
f[j][i][0]=max(f[j][i][0],f[j+k][i-1][0]);//倍增不越界,获取更小长度
f[j][i][1]=min(f[j][i][1],f[j+k][i-1][1]);
}
}
k*=2;
}
}
修改时,区间与区间能覆盖区间,其中,记
int get_max(int l,int r){
int len=(r-l+1);
int k=(log(len+0.5)/log(2));
return max(f[l][k][0],f[r+1-(1<<k)][k][0]);
}
2.lca问题
lca可实现的求出两点的最近公共祖先,用倍增方式,借用RMQ思想,建图如下
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
f[x][0]=fa;
h[x]=h[fa]+1;
for(int i=1;i<=lg[dep[x]];i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int i:v[x]){
if(i==fa) continue;
dfs(i,x);
}
}
其中表示x的两个儿子倍增从跳至
计算部分,先将高度较大的x跳至y的最近距离,后x与y在不相等下一起跳,知道他们的父亲为lca返回父亲
int get_lca(int x,int y){
// if(dep[x]<dep[y]) swap(x,y);
// while(dep[x]>dep[y]) //x处在下面
// x=f[x][lg[dep[x]-dep[y]]-1];
// if(x==y) return x;
// //两侧跳lca
// for(int k=lg[dep[x]]-1;k>=0;k--)
// if(f[x][k]!=f[y][k]){
// x=f[x][k];y=f[y][k];
// }
// if(x==y) return x;
// return f[x][0];
if(dep[x]<dep[y]) swap(x,y);
for(int i=lg[dep[x]]-1;i>=0;i--)
if(dep[f[x][i]]>dep[f[y][i]])
x=f[f[x][i-1]][i-1]; //x往上跳
if(x==y) return x;
for(int i=lg[dep[x]]-1;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];//在同一深度,一起跳
if(x==y) return x;
return f[x][0];
}
计算树上两点之间的距离公式其中,表示i号点到根节点距离,若两条树上最短路相交,则,这条路径总和一定大于等于起点的距离,终点的距离和