点分治(模板)

模板题:
洛谷P3806

题目描述
给定一棵有 n n n 个点的树,询问树上距离为 k k k 的点对是否存在。

输入格式
第一行两个数 n n n, m m m

2 2 2 到第 n n n 行,每行三个整数 u , v , w u, v, w u,v,w,代表树上存在一条连接 u u u v v v 边权为 w w w 的路径。

接下来 m m m 行,每行一个整数 k k k,代表一次询问。

输出格式
对于每次询问输出一行一个字符串代表答案,存在输出 AYE,否则输出 NAY。

数据范围
1 ≤ n ≤ 1 e 4 1 \leq n \leq 1e4 1n1e4 , 1 ≤ m ≤ 100 1 \leq m \leq 100 1m100, 1 ≤ k ≤ 1 e 7 1 \leq k \leq 1e7 1k1e7

Code:

#include <bits/stdc++.h>
using namespace std;
const int MX = 1e4 + 7;
const int MK = 1e7 + 7;

struct Edge{
	int v,w,next;
}e[MX << 1];

int ecnt,head[MX];
inline void add(int u,int v,int w){
	e[++ecnt].v = v;
	e[ecnt].w = w;
	e[ecnt].next = head[u];
	head[u] = ecnt;
}

int n,m,rt,sum,cnt;

int tmp[MX],siz[MX],dis[MX],maxp[MX],q[105];

bool judge[MK], ans[105], vis[MX];

void getrt(int u,int fa){
	siz[u] = 1, maxp[u] = 0;
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].v;
		if(v == fa || vis[v]) continue;
		getrt(v,u);
		siz[u] += siz[v];
		maxp[u] = max(maxp[u],siz[v]);
	}
	maxp[u] = max(maxp[u], sum - siz[u]);
	if(maxp[u] < maxp[rt]) rt = u;
}

void getdis(int u,int fa){
	tmp[cnt++] = dis[u];
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].v;
		if(fa == v || vis[v]) continue;
		dis[v] = dis[u] + e[i].w;
		getdis(v,u);
	}
}

void solve(int u){
	queue<int>que;
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].v;
		if(vis[v]) continue;
		cnt = 0;
		dis[v] = e[i].w;
		getdis(v,u);
		for(int j = 0;j < cnt;++j)
			for(int k = 0;k < m;++k)
				if(q[k] >= tmp[j] && q[k] - tmp[j] >= 0)
					ans[k] |= judge[q[k] - tmp[j]];
		for(int j = 0;j < cnt;++j)
			if(tmp[j] < MK) que.push(tmp[j]), judge[tmp[j]] = true;
	}
	while(!que.empty()){
		judge[que.front()] = false;que.pop();
	}
}

void divide(int u){
	vis[u] = judge[0] = true;
	solve(u);
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].v;
		if(vis[v]) continue;
		maxp[rt=0] = sum = siz[v];
		getrt(v,0);getrt(rt,0);
		divide(rt);
	}
}
int main(){
	scanf("%d %d",&n,&m);
	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);
	}
	for(int i = 0;i < m;++i) scanf("%d",&q[i]);
	maxp[0] = sum = n;
	getrt(1,0);
	getrt(rt,0);
	divide(rt);
	for(int i = 0;i < m;++i)
		if(ans[i]) printf("AYE\n"); else printf("NAY\n");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值