查询树链第K大 。
每个版本的线段树维护的是 从这个节点到 根的 树链的版本, 由于树链第K大,在统计比X 小的数个数时 是可以 进行加减法运算的,所以 就可以用可持久化数据结构。
维护个数时 , sum = f(a) + f(b) - f(c) -f(d) : c 为 a,b 的最近公共祖先, d 为 c 的父亲节点。这样就是 四个版本运算。
同时:二分可以直接在树上跑,判断 左半区域的和 是否大于K,大于K 说明第K大的值 还在 左区间, 相反在右区间里查 第K -sum 大的数。
复杂度 O(nlgn) 如果直接二分区间 复杂度是O(nlgnlgn)。
倍增 LCA 算法:
const int K = 18;
int d[maxn];
int p[maxn][K];
void dfs(int rt,int f){
d[rt]=d[f]+1;
p[rt][0]=f;
int pos = mp[num[rt]];
root[rt] = update(pos,1,n,1,root[f]);
for(int i=1;id[b]) swap(a,b);
if(d[a]=0;i--){
if(p[a][i]!= p[b][i]){
a = p[a][i],b = p[b][i];
}
}
a= p[a][0],b = p[b][0];
}
return a;
}
代码:
#include
#include
#include