欧拉序&树上莫队

树上莫队

方法是用欧拉序转化为序列莫队。欧拉序的具体做法:模拟dfs的过程,把每条边当成两条有向边(根结点上面再加两条边),经过这条边时记录当前边深度大的那个点。每个点在序列中会出现两次,出现的下标记为\(s[i]\)\(t[i]\)。伪代码如下:

void dfs(int x,int fa)
{
  id.push_back(x);
  for(auto u:son[x])
    dfs(u);
  id.push_back(x);
}

对于要查询路径的两个点\(x,y\ (dep_x<dep_y)\),分两类讨论:

\(lca(x,y)=x\),即\(x,y\)在一条链上。此时取\(L=s[x],R=s[y]\),则\([L,R]\)中的出现奇次的点包括了由\(x\)\(y\)路径上的所有点。若按边统计,应特判删除\(x\)

\(lca(x,y)\neq x\),即\(x,y\)位于不同子树内。此时取\(L=t[x],R=s[y]\)(可能要交换\(x,y\)),则\([L,R]\)中出现奇次的点包括\(x\)\(y\)路径上除了\(lca(x,y)\)外的所有点。若按点统计,应特判加入\(lca(x,y)\)

PS:由上面的讨论易知,此种欧拉序不能用于rmq求lca。rmq求lca的欧拉序稍有不同:模拟dfs的过程,把每条边当成两条有向边(根结点上面再加两条边),经过这条边时记录当前边的to节点。每个点在欧拉序中出现了\(deg[i]\)次(显然不能用于树上莫队)。\(pos[i]\)\(i\)号点在序列中第一次出现的位置,则\([pos[x],pos[y]]\)即可保证包括\(x,y\)路径上的所有点。伪代码如下:

void dfs(int x,int fa)
{
  id.push_back(x);
  for(auto u:son[x])
    dfs(u),id.push_back(x);
}
posted @ 2021-06-07 10:21  Swzhao  阅读(115)  评论(0)    收藏  举报