LCA
LCA转rmq:链接
/*
离线版
*/
const int maxn = 10000;
int fa[maxn];
int head[maxn],qhead[maxn];
struct node
{
int to,next,lca;
};
node edge[maxn],qedge[maxn];
int find(int x)
{
if(fa[x]!=x)
fa[x]=find(fa[x]);
return fa[x];
}
bool vis[maxn];
void LCA(int u)//当前节点
{
fa[u]=u;
vis[u]=true;//访问过
for(int k=head[u];k!=-1;k=edge[k].next)
{
if(!vis[edge[k].to])
{
LCA(edge[k].to);
fa[edge[k].to]=u;
}
}
for(int k=qhead[u];k!=-1;k=qedge[k].next)
{
if(vis[qedge[k].to])
{
qedge[k].lca=find(qedge[k].to);//左右节点
qedge[k^1].lca=qedge[k].lca;
}
}
}
ST 。
const int N = 10010; //注意:点标从1开始!!!
int rmq[2*N];//rmq数组,就是欧拉序列对应的深度序列
struct ST
{
int mm[2*N];
int dp[2*N][20];//最小值对应的下标
void init(int n)
{
mm[0] = -1;
for(int i = 1;i <= n;i++)
{
mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
dp[i][0] = i;
}
for(int j = 1; j <= mm[n];j++)
for(int i = 1; i + (1<<j) - 1 <= n; i++)
dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
}
int query(int a,int b)//查询[a,b]之间最小值的下标
{
if(a > b)swap(a,b);
int k = mm[b-a+1];
return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
}
};
//边的结构体定义
struct Edge{
int from,to,next;
}edge[N*2];
int edgenum,head[N];
int F[N*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
int P[N];//P[i]表示点i在F中第一次出现的位置
int cnt;
ST st;
void addedge(int u,int v)//加边,无向边需要加两次
{
Edge E={u,v,head[u]};
edge[edgenum] = E;
head[u] = edgenum++;
}
void dfs(int u,int pre,int dep)
{
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if(v == pre)continue;
dfs(v,u,dep+1);
F[++cnt] = u;
rmq[cnt] = dep;
}
}
void LCA_init(int root,int node_num)//查询LCA前的初始化
{
cnt = 0;
dfs(root,root,0);
st.init(2*node_num-1);
}
int query_lca(int u,int v)//查询u,v的lca编号
{
return F[st.query(P[u],P[v])];
}
void init(){
memset(head,-1,sizeof(head)), edgenum = 0;
}
//LCA_init(root(dfs树根),N(节点数)); query_lca(u,v);

浙公网安备 33010602011771号