点分治基础应用

概述

点分树代表了树上的所有路径,如同分治代表了序列中的所有区间。在点分树节点上统计经过这个点的树链的答案。

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);
	//...
}

距离k联通块修改/询问

此类问题的做法是通用的。

对每个点分树结点开两棵动态开点线段树,一棵记录以结点到自己的距离为关键字的结点信息,另一棵记录以结点到点分树父亲的距离为关键字的结点信息。

由点分树性质,点分树最大深度为\(\log n\)。因此修改、询问时从下往上从节点到点分树根做即可。询问时需要减去结点先到点分树父亲再到当前点分树结点的贡献。总复杂度为\(O(n\log^2n)\)

例题:震波,烁烁的游戏。

树链统计

统计经过每个点分树节点的答案。

结论

点分树可以统计对长度有要求的树链、联通块问题。

posted @ 2018-09-25 21:17  Utoрia  阅读(151)  评论(0编辑  收藏  举报