欧拉序&树上莫队
树上莫队
方法是用欧拉序转化为序列莫队。欧拉序的具体做法:模拟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);
}

浙公网安备 33010602011771号