点分治
简介:
点分治,顾名思义就是基于树上的节点进行分治。
实质就是将一棵树根据合理的分治方法(即改进复杂度),分成若干个子树,化成子问题。
常规操作:
这里要找的分治点即为重心。
根据重心进行划分子树,可以达到log。(具体证明不太想赘述,实则蒟蒻不会证...)
模板(code):
int n;
vector<int>E[N];
int sz[N],F[N];
bool vis[N];
int root,size;
void getroot(int x,int f){
sz[x]=1;
F[x]=0;
SREP(i,0,E[x].size()){
int y=E[x][i];
if(y==f || vis[y])continue;
getroot(y,x);
sz[x]+=sz[y];
chkmax(F[x],sz[y]);
}
chkmax(F[x],size-sz[x]);
if(F[x]<F[root])root=x;
}
void getdeep(int x,int f,/*dep,w,cost,v...*/){
//统计,记录链的信息
SREP(i,0,E[x].size()){
int y=E[x][i];
if(y==f || vis[y])continue;
getdeep(y,x,/*加上该点的信息*/);
}
}
int calc(int x,/*链上需要的信息*/){
int res=0;
getdeep(x,0,/**/);
/*
对刚刚得到这条链的信息具体操作
一般就是按照一定的顺序遍历链,也可能是统计对某个的贡献...
*/
return res;
}
void solve(int x){
vis[x]=1;
ans+=calc(x,/*一般初值为0*/);
SREP(i,0,E[x].size()){
int y=E[x][i];
if(vis[y])continue;
ans-=calc(y,/*该点的信息,容斥,清除y->x的非法答案*/);
root=0;size=sz[y];
getroot(y,0);
solve(root);
}
}
void Clear(){
mcl(vis,0);
size=n;
F[0]=n+1;
root=0;
}