点分治

题目列表:P4178poj1741tree P2634bzoj2152聪聪可可 P3806 P4149 P2664

P4178 树上距离小于等于k的路径数

#include
using namespace std;
#define ll long long
#define MAXN 80005
int n,k;

int cnt,first[MAXN],nxt[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
void add(int a,int b,int c){
	++cnt;
	nxt[cnt]=first[a],first[a]=cnt;
	u[cnt]=a,v[cnt]=b,w[cnt]=c;
}

bool Vis[MAXN];//删点标记 
//树的重心 
int mxflag=0x3f3f3f3f;
int root,sz[MAXN];
void findRoot(int cur,int fa,int N){
	sz[cur]=1;
	int mx=0;
	for(int i=first[cur];i;i=nxt[i]){
		int to=v[i];
		if(to==fa||Vis[to])continue;
		
		findRoot(to,cur,N);
		sz[cur]+=sz[to];
		mx=max(mx,sz[to]);//找到一颗最大的子树 
	}
	mx=max(mx,N-sz[cur]);//旋转180度,把父节点当作子节点,也是一颗子树
	if(mxsz[u]?totsz-sz[u]:sz[v];
		mxflag=0x3f3f3f3f;root=0;//初始化 
		findRoot(to,cur,sz[to]);
		divide(root);
	}
} 

int main(){
	scanf("%d",&n);
	for(int i=1;i

P2634 权值为3的倍数的路径数

#include
using namespace std;
#define ll long long
#define MAXN 40005
int n;

int cnt,first[MAXN],nxt[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
void add(int a,int b,int c){
	++cnt;
	nxt[cnt]=first[a],first[a]=cnt;
	u[cnt]=a,v[cnt]=b,w[cnt]=c;
}

bool Vis[MAXN];//删点标记 
//树的重心 
int mxflag=0x3f3f3f3f;
int root,sz[MAXN];
void findRoot(int cur,int fa,int N){
	sz[cur]=1;
	int mx=0;
	for(int i=first[cur];i;i=nxt[i]){
		int to=v[i];
		if(to==fa||Vis[to])continue;
		
		findRoot(to,cur,N);
		sz[cur]+=sz[to];
		mx=max(mx,sz[to]);//找到一颗最大的子树 
	}
	mx=max(mx,N-sz[cur]);//旋转180度,把父节点当作子节点,也是一颗子树
	if(mxcur这条路径的价值也要处理 不然之后的容斥部分会多减去一些价值
	ans+=rem[0]*(rem[0]-1);
	ans+=rem[1]*rem[2]*2;

	return ans;
}

ll ans;
void divide(int cur){//点分治 
	Vis[cur]=true;
	ans+=calculate(cur,0);
	
	for(int i=first[cur];i;i=nxt[i]){
		int to=v[i];
		if(Vis[to])continue;//从树中删除 
		
		ans-=calculate(to,w[i]);//容斥原理 
		
		//int s=sz[v]>sz[u]?totsz-sz[u]:sz[v];
		mxflag=0x3f3f3f3f;root=0;//初始化 
		findRoot(to,cur,sz[to]);
		divide(root);
	}
} 

ll gcd(ll a,ll b){
	if(b==0)return a;
	return gcd(b,a%b);
}

int main(){
	scanf("%d",&n);
	for(int i=1;i

P3806 距离为k的路径是否存在

#include
using namespace std;
#define ll long long
#define MAXN 20005
int n,m;

int cnt,first[MAXN],nxt[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
void add(int a,int b,int c){
	++cnt;
	nxt[cnt]=first[a],first[a]=cnt;
	u[cnt]=a,v[cnt]=b,w[cnt]=c;
}

bool Vis[MAXN];//ɾµã±ê¼Ç 
//Ê÷µÄÖØÐÄ 
int mxflag=0x3f3f3f3f;
int root,sz[MAXN];
void findRoot(int cur,int fa,int N){
	sz[cur]=1;
	int mx=0;
	for(int i=first[cur];i;i=nxt[i]){
		int to=v[i];
		if(to==fa||Vis[to])continue;
		
		findRoot(to,cur,N);
		sz[cur]+=sz[to];
		mx=max(mx,sz[to]);//ÕÒµ½Ò»¿Å×î´óµÄ×ÓÊ÷ 
	}
	mx=max(mx,N-sz[cur]);//Ðýת180¶È£¬°Ñ¸¸½Úµãµ±×÷×ӽڵ㣬ҲÊÇÒ»¿Å×ÓÊ÷
	if(mxsz[u]?totsz-sz[u]:sz[v];
		mxflag=0x3f3f3f3f;root=0;//³õʼ»¯ 
		findRoot(to,cur,sz[to]);
		divide(root);
	}
} 

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i

P4149 权值为k且节点数最少的路径

#include
using namespace std;
#define ll long long
#define MAXN 400005
int n,k;
 
int cnt,first[MAXN],nxt[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
void add(int a,int b,int c){
	++cnt;
	nxt[cnt]=first[a],first[a]=cnt;
	u[cnt]=a,v[cnt]=b,w[cnt]=c;
}
 
bool Vis[MAXN];//删点标记 
//树的重心 
int mxflag=0x3f3f3f3f;
int root,sz[MAXN],deep[MAXN];
void findRoot(int cur,int fa,int N){
	sz[cur]=1;
	int mx=0;
	for(int i=first[cur];i;i=nxt[i]){
		int to=v[i];
		if(to==fa||Vis[to])continue;
		
		deep[to]=deep[cur]+1;
		findRoot(to,cur,N);
		sz[cur]+=sz[to];
		
		mx=max(mx,sz[to]);//找到一颗最大的子树 
	}
	mx=max(mx,N-sz[cur]);//旋转180度,把父节点当作子节点,也是一颗子树
	if(mx>1;
		if(rem[mid].length>=val)r=mid;
		else l=mid+1;
	}

	if(rem[l].length==val){
		int t=l-1;
		while(rem[t].length==val){
			--t;
		}
		++t;//最优解 
		if(t==o)return ;
		edges[lcadis[rem[t].id]+lcadis[rem[o].id]]+=flag;
	}
}

void calculate(int cur,int val,int val2,int flag){
	rem[0].length=0;
	dis[cur]=val;//顺便初始化 很关键 
	lcadis[cur]=val2;
	
	getDis(cur,-1);

	sort(rem+1,rem+1+rem[0].length,cmp);
	
	for(int i=1;i<=rem[0].length;i++){
		if(rem[i].length>k)break;
		binarySearch(1,rem[0].length,k-rem[i].length,i,flag);
	}
}
 
void divide(int cur){//点分治 
	Vis[cur]=true;
	
	calculate(cur,0,0,1);
	for(int i=first[cur];i;i=nxt[i]){
		int to=v[i];
		if(Vis[to])continue;//从树中删除 
		
		calculate(to,w[i],1,-1);
		
		//int s=sz[v]>sz[u]?totsz-sz[u]:sz[v];
		mxflag=0x3f3f3f3f;root=0;//初始化 
		findRoot(to,cur,sz[to]);
		divide(root);
	}
} 
 
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i

P2664 

 

 

大佬博客:

https://blog.csdn.net/qq_39553725/article/details/77542223

https://www.cnblogs.com/LadyLex/p/8006488.html

https://blog.csdn.net/qq_39553725/article/details/77542223

https://blog.csdn.net/zzkksunboy/article/details/70244945

https://www.cnblogs.com/bztMinamoto/p/9489473.html

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