点分治

作用

当我们遇到一些树上路径问题时,可以想想淀粉质点分治

过程

1.找出当前连通块的重心
2.利用重心将连通块划分为几个块
3.到每个块统计到重心的路径
4.合并路径,统计答案
5.递归到每个块内重复以上操作

我们发现每个点最多会对\(logn\)点贡献,所以复杂度是\(O(n*logn*统计答案复杂度)\)

代码

int dfs(int x,int fa){
	cnt++,d[x]=1;
	for(auto y:son[x])
	if(y.first!=fa&&!vis[y.first]) d[x]+=dfs(y.first,x);
	return d[x];
}//处理子树大小

void prev_work(int x,int fa){
	f[x]=cnt-d[x];
	for(auto y:son[x])
	if(y.first!=fa&&!vis[y.first]) 
	f[x]=max(f[x],d[y.first]),prev_work(y.first,x);
	if(f[x]<f[root]) root=x;
}//找重心

void get(int x,int fa,int dis){
	t.push_back(dis);
	for(auto y:son[x])
	if(y.first!=fa&&!vis[y.first]) get(y.first,x,dis+y.second);
}//统计路径

void calc(int x){
	cnt=0,dfs(x,x),root=x,prev_work(x,x);
	t.clear(),t.push_back(0),b[0]=1;
	for(auto y:son[root]){
		if(vis[y.first]) continue;
		int i=t.size();
		get(y.first,root,y.second);
		for(int q=1;q<=m;q++){
			if(ans[q]) continue;
			for(int j=i;j<t.size();j++)
				if(a[q]>=t[j]&&b[a[q]-t[j]]) {ans[q]=1;break;}//合并路径,求答案
	   }
	   i--;
	   while(++i<t.size())
	   if(t[i]<1e7) b[t[i]]=1;
	}
	vis[root]=1;
	for(auto y:t) if(y<1e7) b[y]=0;
	for(auto y:son[root])
	if(!vis[y.first]) calc(y.first);//递归
	
}

例题

采药人的路径

[2018/7 D班集训]路径规划

posted @ 2026-06-30 10:10  Maple_Mist  阅读(8)  评论(0)    收藏  举报