点分治
作用
当我们遇到一些树上路径问题时,可以想想淀粉质点分治
过程
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);//递归
}

浙公网安备 33010602011771号