简单分治
题目
T1:IOI2017练习赛mountain
找到最高点
选择最高点只能选一边
不选择最高点两边都能选(不冲突)
这种分治就是通过找一些关键点使得两边独立
T2:吃特色菜2
subtask1:显然可以找最小值(瞎jb搞)
subtask2:数据不随机?
每次找到区间终点
区间被分为左边右边以及过分治中心的区间
mini
m
i
n
i
表示第
i
i
位到中最小值,
maxi
m
a
x
i
表示第
i
i
为到分治中心的最大值
对于区间,
min
m
i
n
就是
min(minl,minr)
m
i
n
(
m
i
n
l
,
m
i
n
r
)
,
max
m
a
x
就是
max(maxl,maxr)
m
a
x
(
m
a
x
l
,
m
a
x
r
)
枚举
l
l
的位置,增大时,
min
m
i
n
肯定单调不增,
max
m
a
x
单调不减
q表示q是第一个
maxq
m
a
x
q
>
maxl
m
a
x
l
p表示p是第一个
minp
m
i
n
p
<
maxp
m
a
x
p
假设p < q
i∈[md,p]
i
∈
[
m
d
,
p
]
[l,i]=minl∗maxl
[
l
,
i
]
=
m
i
n
l
∗
m
a
x
l
i∈[p,q]
i
∈
[
p
,
q
]
[l,i]mini∗maxl
[
l
,
i
]
m
i
n
i
∗
m
a
x
l
i∈[q,r]
i
∈
[
q
,
r
]
[l,i]mini∗maxi
[
l
,
i
]
m
i
n
i
∗
m
a
x
i
维护p,q的位置以及前缀和等信息
就能做到O(1)统计答案
这种分治每次处理过分治中心的贡献
得满足可加性
T3:动态最大全1正方形
没有修改可以n^2dp
考虑分治
每次切长边,每次维护过切割线的矩形
每次在切割线上维护一个单调队列(我觉得是单调栈),任然是
O(n2)
O
(
n
2
)
我们考虑每次修改的点对答案的影响
实际上与修改的点在切割线两边的切割线答案肯定是不变的
有可能改变的只是与修改点同侧的切割线
那我们每次只用分治处理需要修改的那一部分
O(knlogn)
O
(
k
n
l
o
g
n
)
T4:ZJOI D2T2 tourist
离线所有询问
每次切长边
对于边上每个点跑一边迪杰斯特拉dijkstra
O(SS−−√logS)
O
(
S
S
l
o
g
S
)
S表示当前分治的面积
树分治
题目
T1:质数长度路径统计
显然树分治
每个子树我们统计
cnt[i]
c
n
t
[
i
]
表示长度为i的路径条数
再统计
sum[i]
s
u
m
[
i
]
表示所有字数长度为i的路径条数
每棵树算的时候用sum计算之后再减去没个子树cnt的计算结果
这里我们还没考虑质数怎么处理,直接做会很慢
应为每次我们都要自己乘自己
上FFT,自己卷自己
O(nlogn2)
O
(
n
l
o
g
n
2
)
T2:采药人的路径问题
给两种颜色分别赋权值1和-1
对每个子树统计g[i]表示和为i的路径条数
考虑前缀和的限制
我们加一维g[i][1..0]第二维表示路径上是否有前缀和为i的一条子路径
一颗颗子树合并即可
O(nlogn)
O
(
n
l
o
g
n
)
T3:紫荆花之恋
du−Ru+dv−Rv<0
d
u
−
R
u
+
d
v
−
R
v
<
0
令
ai=du−Ru
a
i
=
d
u
−
R
u
可以线段树直接统计
加点可能会破坏重心的性质
利用替罪羊树的思想
在点分治树上重构(重新点分治)
O(nlogn2)
O
(
n
l
o
g
n
2
)
T4 cf
在dfs序上dp, O(n2) O ( n 2 )
考虑生成函数
先只考虑一个子树内的生成树
对于一个点v
若为叶子
fv=x+1
f
v
=
x
+
1
若有一个孩子
fv=fu∗x+1
f
v
=
f
u
∗
x
+
1
两个
fv=fu1∗fu2∗x+1
f
v
=
f
u
1
∗
f
u
2
∗
x
+
1
考虑把式子展开了看
假设
bi=fai∗x
b
i
=
f
a
i
∗
x
展开可以得到类似于
(((b1b2+1)∗b3+1)∗b4+1)∗b5+1
(
(
(
b
1
b
2
+
1
)
∗
b
3
+
1
)
∗
b
4
+
1
)
∗
b
5
+
1
令
b1b2
b
1
b
2
为
b1
b
1
,后面都减一
展开为
b1b2b3b4+b2b3b4+b3b4+b4
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(nlogn2)
O
(
n
l
o
g
n
2
)
对整棵树树链剖分
肯定是一条从头到底的重链以及中间分出去的轻链
如果我们能知道轻链分出去的生成函数值
就可以算出根的生成函数值
我要算重链顶端是每个轻边的
∑size∗logn2
∑
s
i
z
e
∗
l
o
g
n
2
总复杂度
O(nlogn3)
O
(
n
l
o
g
n
3
)
T5:UNKOWN
点分治离线操作区间问题
可以对操作建立操作树
然后每次询问一条路径上叉积最大的
离线下来一起处理询问
因为凸包具有可加性
所以对于一个节点把两边的凸包合并起来求解即可
O(nlogn2)
O
(
n
l
o
g
n
2
)
cdq分治
例题
T1:逆序对计数
跳过了
T2:
cdq分治优化dp
计算左边对右边的贡献
每个操作按照a排序,用树状数组维护
T3:百度地图实时路况
O(n4)
O
(
n
4
)
枚举删点做一次floyd
solve(l,r)表示l,r没更新的情况
分治下去即可
O(n3logn)
O
(
n
3
l
o
g
n
)
T4:PACKAGE
也是一样的做法
solve(l,r)
s
o
l
v
e
(
l
,
r
)
左右更新
T5:CASH
在线:
维护方程
Fi=maxFj+aixj+biyj
F
i
=
m
a
x
F
j
+
a
i
x
j
+
b
i
y
j
每次加入一个点,维护凸包,每次在凸包上面二分
O(nlogn)
O
(
n
l
o
g
n
)
离线:
每次处理左边的对右边(可以看做询问)的影响
对于左边建立出凸包,对于右边每个点到左边凸包上二分
O(nlogn2)
O
(
n
l
o
g
n
2
)
瓶颈在二分与排序
我们把询问按照斜率排序
在凸包上答案是单调的
对时间分治
一些性质(需要满足的条件)
基本做法
题目
T1:二维区间和
内部OJ上A过
把修改和询问拆成前缀后缀的相关运算
考虑左边操作对右边询问的影响
可以转化为二维偏序问题
O(nlogn2)
O
(
n
l
o
g
n
2
)
线段树分治
在询问区间可拆解的情况下,把询问拆到线段树节点里
建立线段树过程中离线求答案
题目
T1:向量
这是之前那道点分治的题的弱化板
首先区间可拆解,对每个区间求个max再取max是可行的
按照线段树拆分区间
把每个区间做一个凸包
对于每个询问可以在凸包上二分
考虑复杂度
线段树向量个数是
O(nlogn)
O
(
n
l
o
g
n
)
建立凸包后
O(nlogn2)
O
(
n
l
o
g
n
2
)
二分找
O(Qlogn2)
O
(
Q
l
o
g
n
2
)
考虑线段树的序列可以通过两个儿子序列归并起来
那么就可以快速建凸包
O(nlogn)
O
(
n
l
o
g
n
)
完成建树
对于询问我们可以把每个询问插到对应的区间
再按照斜率排序,然后对每个区间扫一遍
再把每个节点的操作通过ji排序?优化到
O(nlogn)
O
(
n
l
o
g
n
)
?
T2:踩气球
先把线段树建出来
对每个节点设一个0/1变量表示区间内气球是否全部踩爆
再把每个额孩子对应的区间丢到线段树里
那么一个孩子要高兴他在线段数对应的区间里都为1
每次修改只可能把一个叶子结点变为1
当一个节点从0变成1的时候,所有对应的孩子更新一下
O(nlogn+mlogm)
O
(
n
l
o
g
n
+
m
l
o
g
m
)
时间线段树
对时间分治的结构用线段树保存下来,离线处理
题目
T1:离线动态图
显然可以LCT在线维护
离线:
每条边存在的时间是一个区间
把每条边存在的时间丢到线段树里
dfs整个线段树,进入一个节点把所有边加入并查集
dfs到叶子结点后就是某一个时刻的图
这样的话就要删边
可撤销并查集(按秩合并)
O(nlogn2)
O
(
n
l
o
g
n
2
)
T2:来不及
整体二分 来不及讲
陈老师二分
基本概念
题目
T1:tree
每次二分一个值v(可正可负)
每个黑边的权值都+v
求最小生成树
如果黑边个数
i<k
i
<
k
说明v需要更大,反之更小
正确性显然
我们也可以用
(k,vk)
(
k
,
v
k
)
表示k条黑边取v_k的最小生成树的值
会形成一个凸包
这是我们用第一个做法,也就是二分成立的前提
T2:林克卡特树
做法①(数据结构)
首先可以证明答案是凸的(显然)
当然由于这个性质也可以用网络流来做(不过点多爆了)
我们也可以通过网络流的可行性得到答案是凸的这个结论
考虑怎么用数据结构维护
实际上思想是模拟费用流来做
这题实际上有一个在序列上的弱化板
也就是找多少个区间
在序列上用线段树维护模拟反向边什么的过程
O(nlogn)
O
(
n
l
o
g
n
)
考虑搬到树上
用树剖维护
O(nlogn2)
O
(
n
l
o
g
n
2
)
做法②(dp)
显然的三维dp,在树上做背包(会T)
由于答案是有凸性的
我们可以用陈老师二分
仍然二分v,每次开始一条链都要花费v
fi,0..1
f
i
,
0..1
表示当前子树内有没有从下往上的链
每次考虑是否要开始搬一条链
这样是
O(nlogn)
O
(
n
l
o
g
n
)