模拟测试58

T1:

  每个数至多有$2 \sqrt{m}$个约数,也就是说即使$n$很大,在数集中有倍数的数在$m \sqrt{a}$级别。

  可以暴力筛出数集中每个数得约数,用hash表维护一下,可实现$O(1)$查询。

  用$n$减去筛出的数个数即为答案中0的个数,但是注意超过$n$的数要删掉。

  时间复杂度$O(m \sqrt{m})$。

T2:

  我们发现每个物品的花费很大,价值却很小,于是我们可以将价值做背包,求出每个花费对应的最小代价。

  然后将询问离线排序,从时间较早的计划做起。

  将所有商店也排序,从早到晚枚举计划,用单调指针维护当前可以买到东西的商店。  

  如果有新的商店加入,就再做一轮背包DP。

  背包DP同时维护一个花费的后缀最小值,用于二分查询最大的可以获得的价值。

  时间复杂度$O(n^3+mlogn)$。

T3:

  最长路即是树上直径。

  树上直径可以用并查集维护。

  将两个连通块连接,新的直径一定是由原先两条直径的四点中的两点组成的。

  在并查集的代表元素上维护直径的两个端点,合并时分6种情况讨论即可。

  而这六种情况的长度都可以在原树上用lca或树剖求出。  

  但是次题还有上界限制,也就是说我们需要分离并查集。

  用平衡树维护可持久化并查集?

  考虑类似线段树分治的思路。

  对于速度值域开一棵线段树,把每条边像线段树区间查询一样加进去,一条边至多被劈成$log(r-l)$段。

  然后dfs遍历整棵线段树,到一个节点将这个节点的边加上,同时用栈维护加边前并查集的状态。

  回溯时直接弹栈,将并查集连的边分离即可。

  由于要维护结构,并查集不能用路径压缩,只能按秩合并。

  处理出来所有答案,$O(1)$回答询问即可。

  遍历线段树是$O(n)$的,而每次查询是$O(mlogn)$的,所以不能每次都查询。

  由于一共有$m$条边,每条边至多被劈成$logn$段,外加并查集的复杂度$O(logn)$,总的时间复杂度为$O(nlog^2n)$。

posted @ 2019-10-05 15:23  hz_Rockstar  阅读(150)  评论(0编辑  收藏  举报