传送门:https://codeforces.com/contest/686/problem/E
前言:本题解来源于作者某天晚上和一位朋友的发电内容(没错,这个作者直接把自己和朋友发电时发的话用markdown排了一下,传上来了),当时本来就比较口语化,加上作者的做法又实在太过离谱,因此可能语言表述不够清晰,对此深感抱歉qwq;
离谱做法。
首先,如果问题不是三维而是二维的,显然好做一点,使用曼哈顿距离转切比雪夫距离,然后我们的目标就是要将所有点框在一个边长 $2dis$ 的正方形里,令 $dis$ 尽可能小,那 $dis$ 就是 $max(x的范围,y的范围)/2$ 上取整,这是简单的;
考虑三维怎么做。还是考虑曼哈顿转切比雪夫,但只对 $x$ 和 $y$ 做,$z$ 先不管;
(注:以下我说的 $x$ 和 $y$ 就全是转到切比雪夫距离之后的坐标;)
设最终答案坐标为 $(xc,yc,zc)$,对于一个有玫瑰的点 $(xi,yi,zi)$,不妨设 $zi<=zc$,则 $(xc,yc,zc)$ 和 $(xi,yi,zi)$ 的距离为 $|zc-zi|+max(|xc-xi,yc-yi|)$;
此时考虑二分答案 $dis$,考虑怎么 $check$;先不考虑 $zc$ 的值域过大的问题,假设它可以枚举;那么我们可以枚举 $zc$,则要求对于所有 $i$,$|zc-zi|+max(|xc-xi,yc-yi|)<=dis$,分成两个式子就是$|zc-zi|+|xc-xi|<=dis$、$|zc-zi|+|yc-yi|<=dis$;
先说 $x$( $y$ 可以同理):若 $zi<=zc$,则把绝对值去掉之后是 $zc-zi+|xc-xi|<=dis$,$|xc-xi|<=dis-zc+zi$,也就是 $xc$ 需要在区间 $[xi-dis+zc-zi,xi+dis-zc+zi]$ 中;反之若 $zi>zc$,则 $zi-zc+|xc-xi|<=dis,|xc-xi|<=dis-zi+zc$,$xc$ 在区间 $[xi-dis-zc+zi,xi+dis+zc-zi]$ 中;在这两个式子里,$dis$ 和$zc$ 是和当前的 $i$ 无关的,可以单独拎出来,而把这两个值去掉之后的合法区间的交可以预处理,最后给左右端点加/减这两个值就可以了;
于是,假如我们可以枚举 $zc$ 就可以得到做法:把点按照 $z$ 值排序,然后二分 $dis$,$check$ 时枚举 $zc$,弄点线段树或者 $BIT$ 之类支持查询前/后缀的 $max或min(xi-zi或xi+zi)$,就可以支持 $O(log$ $n)$ 查询 $xc$ 的合法区间($yc$ 同理),看看有没有符合条件的点即可 $check$;
但,问题来了。我们枚举不了 $zc$。
但是,我们开心地发现,$zc$ 和所有点的 $zi$ 的相对位置是可以枚举的(因为一共最多就 $n+1$种),而在同一个相对位置段内的 $zc$,求出的$xc、yc$ 合法区间的不同只来源于最后加减的 $zc$,前面预处理的没有 $dis、zc$ 的合法区间、加上 $dis$ 影响之后的合法区间都是一样的;
我们考虑加减 $zc$ 这一步在干什么事;仍然拿 $x$ 举例,刚才的 $xc$ 合法区间是 $[xi-dis+zc-zi,xi+dis-zc+zi]$ $(zi<=zc)$、$[xi-dis-zc+zi,xi+dis+zc-zi]$ $(zi>=zc)$,去掉 $zc$ 之后是 $[xi-dis-zi,xi+dis+zi]$ $(zi<=zc)$、$[xi-dis+zi,xi+dis-zi]$ $(zi>=zc)$;加减 $zc$ 的时候,我们要把第一个区间左端点加 $zc$、右端点减 $zc$(相当于左右各往里缩 $zc$ ),第二个区间右端点加 $zc$、左端点减 $zc$(左右各往外放 $zc$);
容易发现,如果这两个区间进行这一步之前就没有交(也就是没有 $xc$ 可以符合要求),那么进行完这一步还是没交,这种直接扔掉;反之,如果进行这步之前有交,那么进行完仍然有交,除非你在缩放过程中把缩的那个区间给缩没了(左端点大于右端点);所以其实有了四个原区间( $x$ 两个 $y$ 两个)后,我们可以算出符合要求的 $zc$ 区间(需要又在当前枚举的 $z$ 轴相对位置,又不会把两个区间中任何一个缩没),然后这个区间不为空,就完了吗……?
咳,答案是没完。
因为你现在求出的 $xc$ 和 $yc$ 是转完切比雪夫距离的,也就是说是原来的 $(xc+yc,xc-yc)$,容易发现,如果你现在的 $xc$ 和 $yc$ 奇偶性不同,对应的原来的 $xc、yc$ 就不是整点,不符合题目要求,所以对于我们求出的合法 $zc$ 区间,我们可以从左端点开始往右逐个检查;容易发现在我们移动 $zc$ 的时候,原来的两组区间交($x$ 一组 $y$ 一组)只会呈现先变大再变小/从头到尾压根不变两种状态,而且只要有一个大小 $>=2$ 就必定有解了,所以其实你移动一个,有解就是有解,没解就是没解;
遂得到一个 $O(n$ $logA$ $logn)$ 且常数大到发指的做法。预处理不要用线段树,用 $BIT$,即可 $1s$ 过。
细节:缩放区间那段,很可能你缩放前的区间就是一个被缩没了的状态,这种时候不要直接扔掉;有没有合法解,和原区间是不是被缩没了无关,只和 $zc$ 的合法区间为不为空有关,写的时候就直接算出 $zc$ 合法区间,合法区间为空再扔掉,不为空就继续做就好。