标签:cal 节点 math 点分治 span 动态 统计 get 关键字
点分树代表了树上的所有路径,如同分治代表了序列中的所有区间。在点分树节点上统计经过这个点的树链的答案。
int calcn, grasiz, gra;
void getgra(int u, int pa) { // 找当前联通块重心
siz[u] = 1; int maxsiz = 0;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(v == pa || graed[v]) continue;
getgra(v, u);
siz[u] += siz[v];
maxsiz = max(maxsiz, siz[v]);
}
maxsiz = max(maxsiz, cn-siz[u]);
if(maxsiz < grasiz) {
grasiz = maxsiz;
gra = u;
}
}
struct dt_ {
int fa[maxn];
void build(int u, int pa) {
fa[u] = pa; // 点分树结构
graed[u] = 1;
int cn = calcn; // 这个点分树节点对应的联通块大小
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(graed[v]) continue;
grasiz = inf;
if(siz[v] > siz[u]) calcn = cn - siz[u]; //是原树上的父亲
else calcn = siz[v];
getgra(v, u);
build(gra, u);
}
}
}dt;
int main() {
//...
calcn = n; grasiz = inf; // calcn 计算重心的联通块大小
getgra(0, -1);
dt.build(0, -1);
//...
}
此类问题的做法是通用的。
对每个点分树结点开两棵动态开点线段树,一棵记录以结点到自己的距离为关键字的结点信息,另一棵记录以结点到点分树父亲的距离为关键字的结点信息。
由点分树性质,点分树最大深度为\(\log n\)。因此修改、询问时从下往上从节点到点分树根做即可。询问时需要减去结点先到点分树父亲再到当前点分树结点的贡献。总复杂度为\(O(n\log^2n)\)。
例题:震波,烁烁的游戏。
统计经过每个点分树节点的答案。
点分树可以统计对长度有要求的树链、联通块问题。
标签:cal 节点 math 点分治 span 动态 统计 get 关键字
原文地址:https://www.cnblogs.com/utopia999/p/9703589.html