这是一道好题,题意简洁,是多种树上分治结构各显神通的好地方。
WC2018当天晚上去写这题,写到0点,心力憔悴。
后来等到uoj上加了题后,交了若干发,全是97。
今天尝试去补救,发现以前的写法复杂度不太对。
本来LCT splay部分的复杂度是
∑
l
o
g
s
z
i
+
1
s
z
i
=
l
o
g
n
s
z
\sum log \frac{sz_{i+1}}{sz_i}=log\frac{n}{sz}
∑logsziszi+1=logszn
然后access时就不能随便splay一个点,不然复杂度没保证的。
但是我原先的写法,在查找实链上某个点的前驱后继时,是暴力find下去,然后为了保证复杂度,找到后再splay上来,于是就挂了。
现在改写了一下,maintain时维护了下splay的子树中最深点和最浅点,这样交互库调用次数的复杂度就有了保障。
可是代码里仍有一步,暴力爬树完但不splay,然后程序运行复杂度就不知道对不对了。
而且即使交互库调用次数的复杂度正确,也可能被hack,因为LCT理论分析时就自带3倍常数,一开始的随机化并不一定能挽救。
科学的做法还是存在的,如动态点分治。
还有一些其他idea。
一个是比较好写的随机链剖。
具体描述一下就是,每次随机一个未访问过的点,从该点不断往上爬到,直至遇到某个被访问过的点,将这样所形成的路径划分成一条重链状物。
每次在树上点定位时,就在重链上二分,轻边上暴力爬,交互库调用次数复杂度期望是
n
l
o
g
2
n
nlog^2n
nlog2n的。
一个log来源于二分,另一个来源于随机链剖后每个点往上的轻边数量。
下面证一下随机链剖后,一个子树sizez为x的点往上的轻边数量为
O
(
l
o
g
n
x
)
O(log\frac{n}{x})
O(logxn)
考虑一条边v->u(v是u的父亲)成为重边的概率是
s
i
z
e
v
s
i
z
e
u
\frac{size_v}{size_u}
sizeusizev
然后
轻
边
数
量
轻边数量
轻边数量=
d
e
p
−
重
边
数
量
dep-重边数量
dep−重边数量
=
d
e
p
−
∑
s
i
z
e
v
s
i
z
e
u
=dep-\sum \frac{size_v}{size_u}
=dep−∑sizeusizev
≤
d
e
p
−
d
e
p
∗
(
x
n
)
1
d
e
p
\le dep-dep*(\frac{x}{n})^{\frac{1}{dep}}
≤dep−dep∗(nx)dep1(均值不等式)
=
d
e
p
(
1
−
(
x
n
)
1
d
e
p
)
=dep(1-(\frac{x}{n})^{\frac{1}{dep}})
=dep(1−(nx)dep1)
然后试图证明
d
e
p
(
1
−
(
x
n
)
1
d
e
p
)
≤
l
o
g
n
x
dep(1-(\frac{x}{n})^{\frac{1}{dep}})\le log\frac{n}{x}
dep(1−(nx)dep1)≤logxn
两边同除以dep得
1
−
(
x
n
)
1
d
e
p
≤
l
o
g
(
n
x
)
1
d
e
p
1-(\frac{x}{n})^{\frac{1}{dep}}\le log(\frac{n}{x})^{\frac{1}{dep}}
1−(nx)dep1≤log(xn)dep1
现在问题就变成了对于一个
a
≤
1
a\le1
a≤1,是否有
1
+
l
o
g
a
≤
a
1+loga\le a
1+loga≤a。
因为实际上只是要证个
O
O
O,所以用自然对数。
f
(
x
)
=
x
−
l
n
x
−
1
f(x)=x-lnx-1
f(x)=x−lnx−1
f
′
(
x
)
=
1
−
1
/
x
=
1
−
1
/
x
f'(x)=1-1/x=1-1/x
f′(x)=1−1/x=1−1/x
所以其最小值在1处取到,且此时
f
(
x
)
=
0
f(x)=0
f(x)=0
故
a
≤
1
a\le1
a≤1时恒有
1
+
l
o
g
a
≤
a
1+loga\le a
1+loga≤a,证毕。
然后有两个问题,一是动态点分治是基于替罪羊树的思想,那么基于链的分治是不是也可以把splay换成替罪羊树,来少log,并且资瓷动态加叶子呢?
另一个问题是,既然随机链剖可以,那随机点分治呢?而且点分治不用在链上二分,天然少
l
o
g
log
log,看上去更优越。
2018.11.17upd:
尝试了一下随机链剖+用带权treap(关于带权treap的一些理论可以详见18年的集训队论文“浅谈Splay与Treap的性质及其应用”)维护树链,这样可以证明期望复杂度至多是
3
l
n
(
n
)
3ln(n)
3ln(n),但实际上因为放缩得很粗糙,所以还可以更小。
AC代码在此
跑得挺快的
另外因为treap的复杂度是期望而不是均摊,所以中间那步暴力爬树复杂度是对的,至多是
O
(
l
o
g
2
n
)
O(log^2n)
O(log2n)(不一定能利用上带权treap的性质来少log)(我不会证,但倾向于认为
确实是
l
o
g
2
n
log^2n
log2n而不是
l
o
g
n
logn
logn)
但是交互库调用次数的复杂度是明显正确的,常数也不是很大。
具体实现的时候,建议使用
x
1
w
x^\frac{1}{w}
xw1来实现随机数,而不是论文中推荐的
l
o
g
x
w
\frac{logx}{w}
wlogx,主要是这样更便于动态更新点权。