PKUWC2025 D2T1

其实是场上的想到的做法,但是当时被卡 corner case 了 QaQ。

注意到,我们其实可以 \(O(1)\)query 求出 \(x\)\(y\) 的距离。具体地,我们再找三个点,现在有 \(5\) 个点,\(10\) 个距离,而我们又可以 query \(10\) 次,正好可以解出两两距离。这里如果 \(n\le 4\) 特判手玩就好。

然后考虑动态加点,维护直径。如果只维护直径的两个端点 \(x,y\),求距离其实不是很方便。(好像可以 \(10\) 次加三个点,应该就是 Subtask 10?)

考虑存三个点 \(x,y,z\),并且记录 \(\operatorname{dis}(x,y)\)\(\operatorname{dis}(y,z)\)\(\operatorname{dis}(z,x)\)。其中较大的 \(\operatorname{dis}\) 就是直径。我们现在考虑加入 \(i\)

\(x\)\(y\)\(z\) 的中间点为 \(p\),不妨设加入的 \(i\) 是从 \(x-p\) 的链中分叉出来的,分叉点是 \(t\)

那么我们查询一下 \((x,y,i)\)\((y,z,i)\)\((z,x,i)\),然后我们又已知 \(x\)\(y\)\(z\) 两两的距离,其实我们可以解出所有的距离。然后就可以更新直径了。

问题是我们并不知道 \(i\) 是从哪一条链分叉出去,这个也是可以处理的。可以发现,如果是从 \(x-p\) 分叉出去的,那么 \(\dfrac{\operatorname{query}(x,y,i)}{2}-\operatorname{dis}(x,y)=\dfrac{\operatorname{query}(x,z,i)}{2}-\operatorname{dis}(x,z)=e\),并且 \(\dfrac{\operatorname{query}(y,z,i)}{2}-\operatorname{dis}(y,z)\neq e\)

于是我们只要根据上面的条件就可以确定 \(i\) 从哪条链分出去。于是就可以 \(3\) 次加入一个点了。总次数 \(10+3(n-5)=3n-5\)

https://qoj.ac/submission/877333

Upd:

有一个少一些观察的做法。

我们还是动态加点,同时只维护直径的两端点以及距离。

每次加入三个点,那么我们可以用 \(10\)query 求出这五个点两两之间距离。

但是我们已经知道了直径长度,相当于少一个未知数,那么我们也可以少一次 query。于是就可以 \(9\) 次加入 \(3\) 个点。总次数还是 \(3n\) 带一些常数的。

posted @ 2025-01-31 22:13  CJzdc  阅读(41)  评论(0)    收藏  举报