zoukankan      html  css  js  c++  java
  • THUWC 2019 第二轮 纯口胡题解

    从这里开始

    • 比赛目录

      因为各种原因,所以没有去。在场外和神仙 jerome_wei 当嘴巴选手,开心地发现我被打爆了。

      题目大意可以在 ouuan 的游记里查看。

      以下题解应该全是口胡的,应该有很多锅,欢迎来 hack 或者交流做法。

      6 个题,4 个大数据结构。Emm..... 

      听说今年讲题鸽掉了,没进面试也有奖(

    Day 1

    Problem A

      听说是个联赛水题,相信大家都会。

    Problem B

      大概 LCT 维护一下基环树森林就行了。

      谁爱写谁去写

    Problem C

      考虑这样一个问题,把所有标号在 $[l, r]$ 中的点拿出来,任意两个点之间有一条边,距离为树上的距离,求它们的最小生成树,答案等于边权大于 K 的边数加 1。

      有一个结论是,它的最小生成树可以通过按深度排序,每个点在排在它前面的点中找一个距离它最近的点作为父节点的方法求出。

      注意到对于每个点,考虑它和 MST 上父节点的边什么时候会产生贡献。显然存在 $l', r'$ 使得,当 $l leqslant l'$ 或者 $r geqslant r'$ 的时候它会产生贡献。

      考虑怎么求解这样一组数,注意到它们是相互独立的,可以分开求解。

      虑枚举点 $p$,计算它的 $l'$,问题是求满足下面的条件中的点 $x$ 中最大的标号

    • $x < p$
    • $dis(x, p) leqslant K$
    • 在按深度排序后,$x$ 在 $p$ 的前面。

      然后这个硬做只能 $O(nlog^3 n)$。

      考虑按深度排序以深度为第一关键字,标号为第二关键字,然后第三条就变成了 $dep_x leqslant dep_p$。

      考虑从小到达枚举 $p$,用动态点分维护一下信息。考虑现在在分治中心要解决的问题,如果一个点从分治中心的子树内跳进来,我们需要整个分治区域的信息,如果从分治中心子树外跳进来,我们只用分治中心子树的信息。

      分治中心的子树信息只用维护一下每个深度标号的 $max$。考虑子树外对子树内的信息怎么维护,你发现直接查询非常困难,考虑子树外对子树内的影响,注意到子树外每个点对子树内的影响是对一段深度区间产生贡献,这个可以线段树维护。

      对于求解 $r'$ 的过程是类似的,只不过最后一条限制变成 $dep_x > dep_p$,而不是大于等于。

      剩下是个简单扫描线。

      时间复杂度 $O(nlog^2 n + qlog (n + q))$。

    Day 2

    Problem A

      被全场打爆了,群除我人均会 T1,sad....

      考虑只有 1 次操作,你需要最大化或者最小化 $s$,或者小于 0 的最大值和大于 0 的最小值。

      考虑怎么维护这样一个东西

      最大值和最小值只用上面 4 个信息就能转移。

      所以现在的问题是怎么维护最后那两个东西,一个显然的想法是直接维护它们,但是非常显然它是错的。比如小于 0 的最小值在经过某次操作后大于 0,剩下那个值也大于 0,然后就没法转移了。

      注意到每次 $s$ 或变为 $ks + b$,当 $k eq 0$ 的时候,$|ks|$ 的绝对值总是不减的,因此每次操作至多使得绝对值减少 15($k = 0$ 的时候非常 trivial,可以直接判掉)。因此暴力维护 $[-225, 225]$ 之间的每个状态是否可达,以及 $> 225$ 的最小值以及 $< -255$ 的最大值就可以转移了。

      复杂度 $O(2^n n V^2)$。

      听说只记最大最小除了 sub 1 全过了。

    Problem B

      支配树模板题

      考虑求出每个点 $x$ 最早从哪个祖先 $f_x$ 能不经过根到它的路径上的边到达它。求法和求半支配点类似。只不过顺序变成按从根开始依次递归 dfs 序较大的子树处理。

      现在考虑处理询问,某个 $f_x$ 能够到达的话,它的子树内都能到。如果 $f_x$ 的深度比 $a$ 小,并且 $x$ 在 $b$ 的子树内,那么将 $[in_x, out_x]$ 标记为可以到达的。如果一个在 $b$ 的子树内点没有被标记,那么它一定不可达,考虑用反证法,假设 $p$ 是深度最小的不满足条件的点,考虑从根到它的某一条路径,最后一个在根到 $a$ 路径上的点 $q$,之后它不会再经过根到 $p$ 的路径上的边,然后我们得到了 $f_p$ 是 $q$ 的祖先,这和假设矛盾。

      考虑在 dfs 序上离线处理询问,如果一个点的 $f_x$ 比它的某个祖先的 $f_y$ 的浅,那么扫到 $y$ 的时候,$x$ 是否会产生贡献取决于 $y$。然后可以用线段树合并维护一个单调栈状物,询问的时候在线段树上查一个区间和就行了。

    Problem C

      (原本这里还有点东西,因为奇奇怪怪的原因,所以它消失了)

      考虑一下冒泡排序 $k$ 轮候的序列怎么快速求。依次扫描原序列,每扫到一个数就把它加入堆,如果堆的大小超过 $k$ 就 pop 掉其中最小值,并把它加入答案序列,最后 $k$ 个数显然是最大 $k$ 个数从小到大排列。

      考虑当 $q = 1$ 的时候怎么求答案,如果最后 $k$ 个数不满足条件,答案为 0。否则考虑前面的数,每遇到一个数,如果它不是前缀最大值,只能将新加入堆的元素赋为它的值,因为堆内原来的元素都是大于当前前缀 max 的,如果是前缀 max,显然随便分配一个堆内的数给它就行了。所以答案是 $k$ 的前缀 max 个数次方。

      现在考虑 $q leqslant 5 imes 10^5$ 的情形,有一个简单 $O(nlog^2 n + qlog n)$ 做法,考虑点分治,处理跨过分治中心的询问。是否合法可以判断一下最后 $k$ 个的最大值是不是最大的,以及最小值是否比链上剩下的数大。先处理出每个点到分治重心的单调栈内元素个数,以及最大值。维护单调栈可以在插入的时候二分一下,记录一下被修改的元素来做到简单可持久化。然后求剩下一半的时候在求出的单调栈上二分一下就行了。

      好写好调好想,反正常数小,时限 4s,应该能过。

      要做到只带 1 个 log 考虑一下向上走的半边可以每个点向祖先中第一个标号比它大的数连边,然后倍增一下就行了。向下走可以考虑每个点有贡献的条件,实际产生贡献的开始位置大概也可以倍增求一下。

    Day 2+

       是凑个整齐而已,显然这里不会有题解

  • 相关阅读:
    JAVA基础知识之多线程——三种实现多线程的方法及区别
    JAVA基础知识之Collections工具类
    JAVA基础知识之Map集合
    JAVA基础知识之Queue集合
    JAVA基础知识之List集合
    JAVA基础知识之Set集合
    Java基础知识之集合(容器)简介
    JAVA中STL使用
    博客园皮肤
    RMQ
  • 原文地址:https://www.cnblogs.com/yyf0309/p/thuwc2020.html
Copyright © 2011-2022 走看看