总结:点分治学习笔记

版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/82807573

不会点分治的我瑟瑟发抖

点分治:对树进行的一种分层操作。

这种算法的均摊的复杂度是:log

这种算法和树链剖分的区别是

1)树链剖分可以解决待修改问题

2)点分治是解决计数类和全树路径的问题,树链剖分的路径是特殊的

好的我们看一下点分治:

例题:

树中点对统计

这个有~困难

记录某个部分的所有路径然后暴力匹配

这里有个减贡献的问题

这个实际上会被计算是吧QwQ

所以特别减掉这个贡献

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1e5+100;
struct Front_star{
	int u,v,w,nxt;
}e[N<<2];
int cnt=0;
int first[N];
void add(int u,int v,int w){
	++cnt;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].nxt=first[u];
	first[u]=cnt;
}
//
int ans=0;
int n,K;
int All;
int root;
int siz[N];
int vis[N];
int F[N];
void Get_Root(int u,int fat){
	int now=0;
	siz[u]=1;
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==fat||vis[v])continue;
		Get_Root(v,u);
		siz[u]+=siz[v];
		if(now<siz[v])now=siz[v];
	}
//	cout<<u<<" "<<now<<'\n';
	if(now<All-siz[u])now=All-siz[u];
	F[u]=now;
	if(F[root]>now)root=u;
}
int deep[N];
int d[N];
void Get_Deep(int u,int fat){
	deep[++deep[0]]=d[u];
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v]||v==fat)continue;
		d[v]=d[u]+e[i].w;
		Get_Deep(v,u);
	}
}
int Solve(int u,int dep){
	d[u]=dep;
	deep[0]=0;
	Get_Deep(u,0);
	sort(deep+1,deep+1+deep[0]);
	int ret=0;
	for(int l=1,r=deep[0];l<r;){
		if(deep[l]+deep[r]<=K){
			ret+=r-l;
			l++;
		}
		else r--;
	}
	return ret;
}
void DFS(int u){
	vis[u]=1;
	ans+=Solve(u,0);
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v])continue;
		ans-=Solve(v,e[i].w);
		All=siz[v];
		root=0;
		Get_Root(v,0);
		DFS(root);
	}
}
int main(){
//	freopen("test.in","r",stdin);
	F[0]=1e9+7;
	scanf("%d%d",&n,&K);
	for(int i=1;i<n;++i){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
	root=0;
	All=n;
	Get_Root(1,0);
	DFS(root);
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/82807573
今日推荐