2018.7.31分治 (吴瑾昭)

简单分治

题目

T1:IOI2017练习赛mountain

找到最高点
选择最高点只能选一边
不选择最高点两边都能选(不冲突)

这种分治就是通过找一些关键点使得两边独立

T2:吃特色菜2

subtask1:显然可以找最小值(瞎jb搞)

subtask2:数据不随机?
每次找到区间终点
区间被分为左边右边以及过分治中心的区间
m i n i 表示第 i 位到 m i d 中最小值, m a x i 表示第 i 为到分治中心的最大值
对于区间 [ l , r ] , m i n 就是 m i n ( m i n l , m i n r ) , m a x 就是 m a x ( m a x l , m a x r )

枚举 l 的位置, r 增大时, m i n 肯定单调不增, m a x 单调不减
q表示q是第一个 m a x q > m a x l
p表示p是第一个 m i n p < m a x p
假设p < q
i [ m d , p ] [ l , i ] = m i n l m a x l
i [ p , q ] [ l , i ] m i n i m a x l
i [ q , r ] [ l , i ] m i n i m a x i

维护p,q的位置以及前缀和等信息
就能做到O(1)统计答案

这种分治每次处理过分治中心的贡献
得满足可加性

T3:动态最大全1正方形

没有修改可以n^2dp

考虑分治
每次切长边,每次维护过切割线的矩形
每次在切割线上维护一个单调队列(我觉得是单调栈),任然是 O ( n 2 )
我们考虑每次修改的点对答案的影响
实际上与修改的点在切割线两边的切割线答案肯定是不变的
有可能改变的只是与修改点同侧的切割线
那我们每次只用分治处理需要修改的那一部分
O ( k n l o g n )

T4:ZJOI D2T2 tourist

离线所有询问
每次切长边
对于边上每个点跑一边迪杰斯特拉dijkstra
O ( S S l o g S ) S表示当前分治的面积

树分治

题目

T1:质数长度路径统计

显然树分治
每个子树我们统计 c n t [ i ] 表示长度为i的路径条数
再统计 s u m [ i ] 表示所有字数长度为i的路径条数
每棵树算的时候用sum计算之后再减去没个子树cnt的计算结果
这里我们还没考虑质数怎么处理,直接做会很慢

应为每次我们都要自己乘自己
上FFT,自己卷自己
O ( n l o g n 2 )

T2:采药人的路径问题

给两种颜色分别赋权值1和-1
对每个子树统计g[i]表示和为i的路径条数
考虑前缀和的限制
我们加一维g[i][1..0]第二维表示路径上是否有前缀和为i的一条子路径
一颗颗子树合并即可
O ( n l o g n )

T3:紫荆花之恋

d u R u + d v R v < 0
a i = d u R u
可以线段树直接统计

加点可能会破坏重心的性质
利用替罪羊树的思想
在点分治树上重构(重新点分治)
O ( n l o g n 2 )

T4 cf

在dfs序上dp, O ( n 2 )

考虑生成函数
先只考虑一个子树内的生成树
对于一个点v
若为叶子 f v = x + 1
若有一个孩子 f v = f u x + 1
两个 f v = f u 1 f u 2 x + 1
考虑把式子展开了看
假设 b i = f a i x
展开可以得到类似于 ( ( ( b 1 b 2 + 1 ) b 3 + 1 ) b 4 + 1 ) b 5 + 1
b 1 b 2 b 1 ,后面都减一
展开为 b 1 b 2 b 3 b 4 + b 2 b 3 b 4 + b 3 b 4 + b 4
也就是\sum_{i=1}^{}连城_{}^{}
这是可以分治fft(提出一些项,然后分开机选以及合并)
O ( n l o g n 2 )

对整棵树树链剖分
肯定是一条从头到底的重链以及中间分出去的轻链
如果我们能知道轻链分出去的生成函数值
就可以算出根的生成函数值
我要算重链顶端是每个轻边的 s i z e l o g n 2
总复杂度 O ( n l o g n 3 )

T5:UNKOWN

点分治离线操作区间问题

可以对操作建立操作树
然后每次询问一条路径上叉积最大的
离线下来一起处理询问

因为凸包具有可加性
所以对于一个节点把两边的凸包合并起来求解即可
O ( n l o g n 2 )

cdq分治

例题

T1:逆序对计数
跳过了

T2:
cdq分治优化dp
计算左边对右边的贡献
每个操作按照a排序,用树状数组维护

T3:百度地图实时路况
O ( n 4 ) 枚举删点做一次floyd

solve(l,r)表示l,r没更新的情况
分治下去即可
O ( n 3 l o g n )

T4:PACKAGE
也是一样的做法
s o l v e ( l , r 左右更新

T5:CASH
在线:
维护方程 F i = m a x F j + a i x j + b i y j
每次加入一个点,维护凸包,每次在凸包上面二分
O ( n l o g n )
离线:
每次处理左边的对右边(可以看做询问)的影响
对于左边建立出凸包,对于右边每个点到左边凸包上二分
O ( n l o g n 2
瓶颈在二分与排序
我们把询问按照斜率排序
在凸包上答案是单调的

对时间分治

一些性质(需要满足的条件)
基本做法

题目

T1:二维区间和
内部OJ上A过

把修改和询问拆成前缀后缀的相关运算
考虑左边操作对右边询问的影响
可以转化为二维偏序问题
O ( n l o g n 2 )

线段树分治

在询问区间可拆解的情况下,把询问拆到线段树节点里
建立线段树过程中离线求答案

题目

T1:向量
这是之前那道点分治的题的弱化板
首先区间可拆解,对每个区间求个max再取max是可行的

按照线段树拆分区间
把每个区间做一个凸包
对于每个询问可以在凸包上二分

考虑复杂度
线段树向量个数是 O ( n l o g n ) 建立凸包后 O ( n l o g n 2 )
二分找 O ( Q l o g n 2 )
考虑线段树的序列可以通过两个儿子序列归并起来
那么就可以快速建凸包 O ( n l o g n ) 完成建树

对于询问我们可以把每个询问插到对应的区间
再按照斜率排序,然后对每个区间扫一遍
再把每个节点的操作通过ji排序?优化到 O ( n l o g n )

T2:踩气球
先把线段树建出来
对每个节点设一个0/1变量表示区间内气球是否全部踩爆
再把每个额孩子对应的区间丢到线段树里
那么一个孩子要高兴他在线段数对应的区间里都为1
每次修改只可能把一个叶子结点变为1
当一个节点从0变成1的时候,所有对应的孩子更新一下
O ( n l o g n + m l o g m )

时间线段树

对时间分治的结构用线段树保存下来,离线处理

题目

T1:离线动态图
显然可以LCT在线维护
离线:
每条边存在的时间是一个区间
把每条边存在的时间丢到线段树里
dfs整个线段树,进入一个节点把所有边加入并查集
dfs到叶子结点后就是某一个时刻的图
这样的话就要删边
可撤销并查集(按秩合并)
O ( n l o g n 2

T2:来不及

整体二分 来不及讲

陈老师二分

基本概念

题目

T1:tree
每次二分一个值v(可正可负)
每个黑边的权值都+v
求最小生成树
如果黑边个数 i < k
说明v需要更大,反之更小
正确性显然

我们也可以用 ( k , v k 表示k条黑边取v_k的最小生成树的值
会形成一个凸包
这是我们用第一个做法,也就是二分成立的前提

T2:林克卡特树
做法①(数据结构)
首先可以证明答案是凸的(显然)
当然由于这个性质也可以用网络流来做(不过点多爆了)
我们也可以通过网络流的可行性得到答案是凸的这个结论
考虑怎么用数据结构维护
实际上思想是模拟费用流来做
这题实际上有一个在序列上的弱化板
也就是找多少个区间
在序列上用线段树维护模拟反向边什么的过程
O ( n l o g n )
考虑搬到树上
用树剖维护 O ( n l o g n 2 )

做法②(dp)
显然的三维dp,在树上做背包(会T)
由于答案是有凸性的
我们可以用陈老师二分
仍然二分v,每次开始一条链都要花费v
f i , 0..1 表示当前子树内有没有从下往上的链
每次考虑是否要开始搬一条链
这样是 O ( n l o g n )

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/81349858
今日推荐