警示后人,如果你全 WA
查看原帖
警示后人,如果你全 WA
534562
liheyang123楼主2025/7/22 22:44

思路是 构建圆方树 + 倍增 LCA + tarjan 求解仙人掌上的最短路,记录每个点所处的环的长度与到环 dfn 最小处的距离,与各点到圆方树树根的距离。

如果你考虑 LCA 是方点的情况代码如下:

//circle[i] 是 i 所处环的长度,newdis[i] 是 i 到圆方树根的距离。
int Tu, Tv, valu, valv;
for(auto Edge : T[lca]){
	int to = Edge.first;
	if(get_lca(to, u) == to) Tu = to, valu = Edge.second; 
	if(get_lca(to, v) == to) Tv = to, valv = Edge.second; 
}
int w = min(circle[Tu] - valu - valv, valv + valu);
if(circle[Tu] - valu - (circle[Tu] - valv) > 0) w = min(circle[Tu] - valu - (circle[Tu] - valv), w);
if(circle[Tu] - valv - (circle[Tu] - valu) > 0) w = min(circle[Tu] - valv - (circle[Tu] - valu), w);
write(newdis[u] - newdis[Tu] - newdis[Tv] + newdis[v] + w);

这会出现 Tu, Tv 不同侧的问题,所以建议加入数组判断在两者到环顶是否有公共部分,然后特判。

if(fl[Tu] == fl[Tv]){
    if(circle[Tu] - valu - (circle[Tu] - valv) > 0) w = min(circle[Tu] - valu - (circle[Tu] - valv), w);
    if(circle[Tu] - valv - (circle[Tu] - valu) > 0) w = min(circle[Tu] - valv - (circle[Tu] - valu), w);
}

这个 fl 的判断实现并不难,tarjan 加入下述代码即可。

// dis 是到原仙人掌的根的距离
if(dis[x] - dis[u] < circle[u] - dis[x]) fl[x] = 1;
2025/7/22 22:44
加载中...