我去了P营,但隔壁好像很有意思,于是我也来更题解辣!/se
题面来自xht。
DAY1
T1
这道题简单。
T2
这道题比较难写,我觉得如果是我可能就跳了。
大概是一个基环树+LCT,怪恶心的。
T3
这道题稍微有意思一点,感觉区分度主要在这道题上面。
容易发现,你如果求一个最小生成树的话,那么答案就是大于
X
X
X的边加一。
那么我们考虑这样子求,按照深度排序,每个点按顺序加进来,往前面连边,这个就类似于建出一个树的结构,每个点的贡献考虑设为他跟他父亲的那一条边有没有连边。
那么像当于一个点
x
x
x我们求出一个
L
x
L_x
Lx,一个
R
x
R_x
Rx,以
L
x
L_x
Lx为例,找到一个最大的
L
x
L_x
Lx满足:
d
e
p
L
x
<
d
e
p
x
,
L
x
<
x
,
d
i
s
(
L
x
,
x
)
≤
X
dep_{L_x}<dep_x,L_x<x,dis(L_x,x)\le X
depLx<depx,Lx<x,dis(Lx,x)≤X
R
x
R_x
Rx就是找到一个最小的
R
x
R_x
Rx满足:
d
e
p
R
x
≤
d
e
p
x
,
R
x
>
x
,
d
i
s
(
R
x
,
x
)
≤
X
dep_{R_x}\le dep_x,R_x>x,dis(R_x,x)\le X
depRx≤depx,Rx>x,dis(Rx,x)≤X
因为有同一层的情况,所以一个带等号,一个不带。
这个东西正着做是
O
(
n
log
2
n
)
O(n\log^2n)
O(nlog2n),我们反过来做就就可以
O
(
n
log
n
)
O(n\log n)
O(nlogn)。
问题是求
L
x
,
R
x
L_x,R_x
Lx,Rx,这是一个树上的问题,并且他还带距离限制,容易想到点分治。
我一开始的想法是,按照标号排序,一个一个点加进来,对于每个分治中心,和分治中心的所有孩子都维护一个可持久化线段树,这实际上好像是不能做的。。。
那么我们可以按照深度排序,一个一个点加进来,对于每个分治中心,我们以标号为下标维护一个可持久化线段树,线段树上维护一个最小值即可,然后询问就是一个线段树上二分。
于是复杂度就是
O
(
n
log
2
n
+
q
log
n
)
O(n\log^2n+q\log n)
O(nlog2n+qlogn)。
DAY2
这个T2的题意错了,他的非树边不一定是祖先连到孩子的,但保证整个图是个DAG。
T1
这道题还行,但据说现场被假做法水过了。
容易发现,所有的函数按正负性讨论之后都会是一个
k
x
+
b
kx+b
kx+b的形式。
我们需要维护的只是最小值,最大值,小于0的最大值,大于0的最小值。
直接
d
p
dp
dp有那么一丢丢的问题,那就是后面两个东西不是很好搞。
我们可以发现,你不考虑
k
=
0
k=0
k=0的情况,如果这个值很大的话。这个值的正负形变化就只跟
k
k
k的正负性相关了。
那么也就是说我们只需要维护
[
−
255
,
255
]
[-255,255]
[−255,255]以内的值,再维护最小值最大值,小于
−
255
-255
−255的最大值,大于
255
255
255的最小值。
T2
说实话我个人感觉这个题是DAY2中最简单的,据去T营的rose哥哥说,主要是这个题有比较大的误导性,导致很多选手可能想错了。最主要我一开始看了错误的题意,导致我迅速的往正解的思路去思考了。。。
假设只有祖先连到孩子的边。
我们考虑对于一条路径
a
−
>
b
a->b
a−>b,一个点
x
x
x有贡献是怎样的,我们求出
x
x
x往上的
d
e
p
dep
dep最小的点
u
p
x
up_x
upx可以通过非树边到达
x
x
x。
那么我们要判断一个
x
x
x是否合法就是判断点
x
x
x及
x
x
x到
b
b
b的祖先中是否存在一个点的
u
p
up
up满足它的
d
e
p
dep
dep小于
a
a
a。
有横叉边
x
−
>
y
x->y
x−>y会怎么样,首先按拓扑序一个一个把点加进来,两个点求个LCA之后显然
x
x
x这个点往上到LCA的所有点都是可以给
y
y
y走的,因为他肯定不会影响
y
y
y,因此只用做一个链的求最小值,如果写倍增的话应该是比较好写的。
求出了
u
p
x
up_x
upx之后,剩下要做的事情可能就是一个线段树合并了,我们以
d
e
p
u
p
dep_{up}
depup的最小值作为下标,存这个
d
e
p
dep
dep的含有多少点即可。
T3
这个题也有点意思。
一开始容易想到一道题,就是「2017 山东三轮集训 Day1」Fable。
以下的
k
k
k都是原
k
+
1
k+1
k+1。
考虑一个序列他会把前
k
k
k个的最小值放在第一位,前
k
+
1
k+1
k+1个的最小值放在第二位,那么我们就可以得到一个简单的
O
(
q
n
)
O(qn)
O(qn)做法,计数的部分是ez的。
实际上你瞎鸡儿推一下这个计数过程发现:设
s
s
s为他除掉后面
k
k
k个数之后的前缀最大值个数,则方案数是
k
s
k
!
k^sk!
ksk!。
我们现在需要求前缀最大值个数。
如果我们使用楼房重建那题类似的做法,使用倍增,那么可以做到
O
(
n
log
2
n
+
q
log
2
n
)
O(n\log^2n+q\log^2n)
O(nlog2n+qlog2n)。
上面倍增的做法被我放弃了,我并没有细想优化。
于是我们考虑点分治的做法。
我们现在把每个询问挂在这两个点分治中心的LCA上面。
我们考虑对于一个LCA我们需要维护往上的链和往下的链,先考虑往下的链,我们先求出每个点到根的前缀最大值的个数,这个直接做就好。
对于一个询问,假设我们得出往上的链的最大值,我们考虑二分得出这条链上第一个比这个值大的数,可以得知,这个数肯定是前缀最大值,因此我们直接做一个减法就可以得到往下的情况。
接下来考虑左边的,考虑dp,我们考虑求出每个点往上的第一个比他大的值,然后直接继承即可,但是求出这个会使复杂度变为
O
(
n
log
2
n
)
O(n\log^2n)
O(nlog2n)。
那么我们考虑一个点分树,他分为分治中心树内和树外两种情况,对于树内的情况,我们考虑直接预处理出每个点在原树中第一个比他大的点,这一步是
O
(
n
log
n
)
O(n\log n)
O(nlogn)的。
问题是树外的点,我们考虑这样的情况。
我们对于原本是属于分治中心(红色点)的祖先节点的点,称这个为祖先链,维护一个单调栈,由于路径是唯一的,所以复杂度明显ok。
对于黄色的点,假设我们预处理出的他在原树中的第一个比他大的值不属于这一条链,那么我们把黄色点mark一下先不管他把它的dp值设为0,然后假设黄色点的儿子节点来继承的时候,我们给继承他的孩子mark上他的标记,这样dp下去。
然后如果继承黄色点的孩子节点有询问了,那么这时我们在黄色点的单调栈上二分,得到祖先链上第一个比他大的值即可。得到注意此时由于黄色点跟他的孩子都属于同一个分枝,所以他们的单调栈都是一样的。
因此复杂度是
O
(
n
log
n
+
q
log
n
)
O(n\log n+q\log n)
O(nlogn+qlogn)。
其实我的做法就是用了一些小技巧就把复杂度省下来了,但是感觉我想了挺久的。。。