树分治(点分治)

点分治主要能解决的问题是树上路径个数的问题。

分治也并没有想象中的那么难,就是时间复杂度有点玄学,有的人说是nlog^2n有的说是nlogn,我也不知道具体是多少(反正比n^2暴力快就是了)

点分治的思想就是每次取一个重心,然后把每个经过该重心的路径数量算出来(要用容斥,注意重心是否要被计算),对于重心的每个儿子都递归进去做同样的操作,最后累加即可(看代码就懂了)。

扔道题

题意就是求长度不超过k的路径的数量总数。

代码:

#include
#include
#include
using namespace std;
const int N = 200005;
struct A{
	int v,c,next;
}e[N];
int p[N],q[N],dep[N],size[N],msize[N],vis[N],n,K,eid,l,r;
void init(){
	memset(p,-1,sizeof(p));
	memset(vis,0,sizeof(vis));
	l=r=0;
	eid=0;
}
void add(int u,int v,int c){
	eid++;
	e[eid].v=v;
	e[eid].c=c;
	e[eid].next=p[u];
	p[u]=eid;
}
void dfs(int x){
	q[++r]=x;
	vis[x]=1;size[x]=1;msize[x]=0;
	for(int i=p[x];i+1;i=e[i].next){
		int v=e[i].v;
		int c=e[i].c;
		if(vis[v]) continue;
		dep[v]=dep[x]+c;
		dfs(v);
		size[x]+=size[v];
		msize[x]=max(msize[x],size[v]);
	}
	vis[x]=0;
}
bool cmp(int x,int y){
	return dep[x]i&&dep[q[i]]+dep[q[j]]>K) j--;
		ans+=j-i;
	}
	return ans;
}
int work(int x){ //主题
	l=1,r=0;
	dfs(x);
	int top=size[x],mi=msize[x];
	for(int i=1;i<=r;i++){//找重心(保证log级)
		int v=q[i];
		if(max(msize[v],top-size[v])

 

你可能感兴趣的:(点分治)