模拟测试20191026
$T1:666$
开始以为是数学
打了个表发现步数不超过$50$
直接模拟就好了诶
枚举步数,每次扫所有点尽量往后走就好了
$T2:123567$
考场$40pts$后就失去梦想了啊
正解是大神杜教筛(%%%大神$DeepinC$
先看$40pts$的柿子
$$\sum_{i=1}^{\sqrt n}\mu_{i} \times \frac{n}{i\times i}$$
看后边这个$\frac{n}{i\times i}$,是不是和某些东西有点像?
没错,除法分块!
可以发现$1e18$在这样的除法分块下只有约$188$万种取值
$\mu$ 可以直接杜教筛求前缀和
1 for(ll i=1,j;i*i<=n;i=j+1){
2 j=sqrt(n/(n/i/i));
3 ans+=(n/i/i)*(S(j)-S(i-1));
4 }
T3:椎
考场$YY$一棵$Treap$然而暴毙了
正解线段树维护单调栈
我们考虑大根堆$Treap$的结构
1,如果把所有点按照$key$排序的话,他们的$lca$就是他们之间$val$最大的点
2,一个点$i$的深度就是 $从左维护单调栈到i时栈内数的个数+从右开始维护单调栈到i时栈内数的个数-1$
用线段树维护单调栈就可以了
怎么维护?
考虑$solve(l,r,v)$表示把$v$放入区间$[l,r]$的单调栈内后的单调栈
既然是线段树,那主要难点在于怎么合并两个区间
现在我们以左边为例分两种情况考虑
$1,[l,r]\subseteq 当前查询区间$
(1) 插入值$\geq$右区间最大值
直接递归查询左边,即调用$solve(l,mid,v)$,因为右边一定都被弹出
(2) 插入值$<$右区间最大值
先递归查询右边,即调用$solve(mid+1,r,v)$,然后把右边最大值插入并递归查询左边,即调用$solve(l,mid,max_{rc})$
后面的操作维护的就是把右边插入左边后左边剩余个数
$2,[l,r]\cap 当前查询区间$
优先查询右边,即调用$solve(mid+1,r,v)$,同时用一个全局变量维护已经查询过的区间的最大值$lst$_$max$
然后如果$[l,mid]\cap 当前查询区间$ 把现在这个最大值扔到左区间查询,即调用$solve(l,mid,lst$_$max)$
最后就得到了$solve(l,r,v)$
但是这样复杂度不对,因为情况1有可能扫了整个被查询区间,复杂度退化成了$O(n^{2})$
然而我们发现1(2)情况中调用的$solve(l,mid,max_{rc})$和v无关
那么我们可以在插入一个数时把这玩意预处理出来
复杂度$O(nlog^{2}n)$