对于链分治。
每次不仅要处理轻儿子到每个点的贡献,重链中的互相贡献也需要计算。
对于树剖,每条链上它是用一个线段树来维护贡献的。但是复杂度还是O(logl)O(\log l)O(logl),如果出题人把lll和hhh(重链长度和深度)平均一下,那么就可以被卡成O(log2n)O(\log^2 n)O(log2n)
对于LCT,我们很难处理它过大的常数。
那么我们还是考虑树剖。
仔细分析可以发现线段树维护是有一点浪费的,
如果有一个点轻儿子总sizesizesize过大,那么仍然把这个点雪藏在其重链所在线段树最后一层是不优的。
我们可以用平衡树来维护一条重链然后把这个点放在平衡树根的位置。
可是现在还是O(log2n)O(\log^2 n)O(log2n)的。
我们可以沿用这个思想,把平衡树的形态偏向轻儿子sizesizesize大的一方。
具体方法为:
对于一条重链,每个点的权值设为它的轻儿子的sizesizesize之和+1(加不加一不重要,只是这样好算:val=sz[x]−sz[sonx]val=sz[x]−sz[sonx]val=sz[x]−sz[sonx],找到带权重心后,把它作为这一层结点,递归左右区间建立左右儿子。
重链之间的虚边按照原树形态建就好了。
考虑这样建出来的树,每次向上跳一次(虚边/实边),轻儿子的总sizesizesize至少翻一倍,所以树高是logn\log nlogn的。
所以就是每条重链我们不按它的重心来分治,我们按加上子树sizesizesize的带权重心来分治,这样可以得到总O(logn)O(\log n)O(logn)的优秀复杂度。
QTREE IV 全局平衡二叉树解法:
#include<bits/stdc++.h>
#define maxn 100005
#define inf 0x3f3f3f3f
using namespace std;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cst[maxn<<1],cnt_e;
void Node(int u,int v,int c){
Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=c; }
int n,m;
int val[maxn],sum[maxn],lm[maxn],rm[maxn],mx[maxn],fa[maxn