大意:有一棵树,有m条线路,给出q个询问u->v最少通过几条线路到达。
解法:贪心求u和v到lca最少跳几次,然后判最后一次是否通过同一条线路到达。通过倍增法到达logN级别,最后的特判是用树状数组达到logN级别。
对于每一个节点,其子树代表的区间为dfn[v]到dfn[v]+sz[v],对于需要特判的一组(u,v),在dfs到u的时候把起点为u的路的终点+1,相当于有一条路从u戳到某一个区间(即某一个节点的子树中),最后判断v的子树中是否有从u的子树中戳过来的路,如果有那么就存在u->v的一条线路。对于哪些(u,v)是需要特判的呢?因为程序中求的是u和v还差一次才跳到lca的次数a和b,因此如果u或者v本身就是lca那么就不需要特判。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
scanf("%d", &q);
for(int i = 0;i < q;i++)
{
scanf("%d%d", &u, &v);
if (!reachable(u, v))bad[i] = true;
_lca = lca(u, v);
ans[i] = calc_cnt(u, _lca) + calc_cnt(v, _lca);
if (u != _lca)ans[i]++;
if (v != _lca)ans[i]++;
if (u != _lca && v != _lca)query[u].push_back({ v,i });
}
solve(1);
for (int i = 0;i < q;i++)
{
printf("%d\n", bad[i] ? -1 : ans[i]);
}
return 0;
}