【题解】Solution Set - NOIP2024集训Day17 整体二分

【题解】Solution Set - NOIP2024集训Day17 整体二分

https://www.becoder.com.cn/contest/5488


二逼平衡树 /【模板】树套树

rt. 树套树。


「国家集训队」矩阵乘法

整体二分板子。

如果每次二分的时候都 O(n2) 重新算二维前缀的话,时间复杂度是 O(n3logn+qlogn)。非常卡(实际上没分)。

考虑记录每个元素的值和坐标,然后排序。

每次把权值在 [l,mid] 内的加入到一个二维树状数组中,然后再查询。

因为:

  1. 每层每个点会且仅会被加入一次;
  2. 每层每个询问会且仅会询问一次;

每次修改和查询都是 O(log2n),一共 logn 层,所以总时间复杂度为 O((n2+q)log3n)


「BalticOI 2004」Sequence 数字序列

做过。

对于一个 bi 如果在决定取 x,x+1 的时候,其实确定的是一种趋势。比如选择了 x 那么最终 b 的取值一定 x

所以我们考虑整体二分。

注意到我们求出的 b 是满足的不减的。

输入时 aiaii,输出时再把 i 加回去,就可以保证 b 严格单增了。


「HNOI2015」接水果

一句话题意:

给定一棵树上的一堆路径,路径有权值。每次询问给定一个路径问这条路径的子路径权值第 k 小。


难点在于怎么判断水果 (u,v) 是否包含盘子 (x,y)。(不妨 dfn[u]<dfn[v]dfn[x]<dfn[y]

一条路径 (u,v) 包含 (x,y) 的充要条件为 S

分讨:(这个分讨其实感觉还挺难想到的,可以当成一个 trick 吧

  1. lca(x,y)=x。(显然 y 一定是不能作为 lca(x,y) 的。
    z 为从 xy 路径上的第一个点。
    那么:

    S{dfn[u][1,st[z])dfn[v][st[y],ed[y]]{dfn[u][st[y],ed[y]]dfn[v](ed[z],n]

  2. lca(x,y)x

    那么:

    S{dfn[u][st[x],ed[x]]dfn[v][st[y],ed[y]]

所以每个盘子可以视作一个矩形,水果视作一个点。

每次询问就是问包含这个点的那些矩形中权值第 k 大,离线整体二分,每次扫描线即可。


「HNOI2016」网络

每次询问,我们二分答案,check 的话就是看重要程度 >mid 的是不是都被影响。

直接对于所有 >mid 的路径 +1,然后看这个故障点是不是被覆盖了这么多次。

然后直接整体二分就行了啊。

每次我们其实只需要判断 [mid,r] 因为值域大于 r 的都已经判过是都被影响的了,这样就保证了时间复杂度。

如果直接树剖的话是 O(nlog3n) 的。

直接用一个 bit 维护子树和,然后每次差分修改。

这样单次路径修改就变成了 O(log2n)

总的时间复杂度为 O(nlog2n)


「P5163」 WD与地图

先把所有操作倒过来,把断边转化为连边。

然后每个连通块维护一颗权值线段树,然后线段树合并就行了。

关于线段树合并的时间复杂度:

一次完整的线段树合并的时间复杂度 = 初始状态下叶子节点的个数 × logVV 是线段树的值域。


Why?

对于最终状态的线段树上的每一个点,之前合并的时候每访问一次这个节点,一定是会合并两个叶子节点的。而且必须存在两个叶子节点来给她合并,也就是说每个节点至多会被访问的次数是其 子树的叶子节点的个数

这样一来每层的访问次数总和就是叶子节点个数,而一共 logV 层,所以结论成立。


所以,这道题线段树合并的时间复杂度整体是 O(nlogn) 的。

但是好像不需要整体二分?直接做就好了?


哦,原来是有向图啊。😅

有点难办,要维护强连通分量。


pyt 告诉我的一个很聪明的想法。

如果我们知道了每次询问前的强连通分量的状态,当然可以按照之前无向图的方法来解决。

其实,我们只需要知道「每一条边第一次两端同属一个强连通分量的时间」。

显然这个时间是不早于这条边加入的时间的。

所以我们就可以直接这个时间排序(如果这个时间相同,按原始时间排),按照无向图的方式,每次线段树合并,然后查询就行了。


现在就是要求解这个时间了。

都出现「第一次」了,所以这个时间一定是有单调性的。

考虑整体二分。

我们每次把原始时间小于等于 mid 的边及其两端的点单独拎出来,跑一遍 tarjan(这样就保证了时间复杂度)。

然后每一条边看其两端是否在同一强连通分量里面,就没了。


总结一下,听了解法之后,感觉挺对的。但是真的很难想到去求「每一条边第一次两端同属一个强连通分量的时间」这个东西。


关于实现:(其实也挺精妙的。

我们可以直接在每一次 solve 出口的时候,直接用并查集和线段树合并维护强连通分量(不需要撤销),这样每次不管是在算答案的时候,还是跑 tarjan 的时候(每条边的两个端点都重新赋值成其强连通分量内部的代表点)前面的边的贡献都是恰好对的。

posted @   CloudWings  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示