P3806 【模板】点分治1

(color{#0066ff}{题目描述})

给定一棵有n个点的树

询问树上距离为k的点对是否存在。

(color{#0066ff}{输入格式})

n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径

接下来m行每行询问一个K

(color{#0066ff}{输出格式})

对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)

(color{#0066ff}{输入样例})

2 1
1 2 2
2

(color{#0066ff}{输出样例})

AYE

(color{#0066ff}{数据范围与提示})

对于30%的数据n<=100

对于60%的数据n<=1000,m<=50

对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000

(color{#0066ff}{题解})

每次找重心,删去递归子树

对于每个子树,dfs出到子树根(重心)的距离

对于同一子树的,会有重复的路径,那不是答案,但是也统计了,所以在枚举孩子的时候要减回去,这部分答案在递归子树的时候会被统计

每次把所有的子树的dis扔进数组里

(O(n^2)收集答案)

#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL in() {
	char ch; int x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
struct node {
	int to, dis;
	node *nxt;
	node(int to = 0, int dis = 0, node *nxt = NULL): to(to), dis(dis), nxt(nxt) {}
	void *operator new (size_t) {
		static node *S = NULL, *T = NULL;
		return (S == T) && (T = (S = new node[1024]) + 1024), S++;
	}
};
const int maxn = 2e5 + 10;
int f[maxn], tmp[maxn], dis[maxn], siz[maxn], can[maxn];
bool vis[maxn];
node *head[maxn];
int n, sum, m, root, num;

void add(int from, int to, int dis) {
	head[from] = new node(to, dis, head[from]);
}
void getdis(int x, int fa, int d) {
	tmp[++num] = d;
	dis[x] = d;
	for(node *i = head[x]; i; i = i->nxt)
		if(i->to != fa && !vis[i->to]) 
			getdis(i->to, x, d + i->dis);
}
void calc(int x, int d, int flag) {
	num = 0;
	dis[x] = d;
	getdis(x, 0, dis[x]);
	for(int i = 1; i <= num; i++)
		for(int j = 1; j <= num; j++)
			if(i != j)
				can[tmp[i] + tmp[j]] += flag;
}
void getroot(int x, int fa) {
	siz[x] = 1;
	f[x] = 0;
	for(node *i = head[x]; i; i = i->nxt) {
		if(i->to == fa || vis[i->to]) continue;
		getroot(i->to, x);
		siz[x] += siz[i->to];
		f[x] = std::max(f[x], siz[i->to]);
	}
	f[x] = std::max(f[x], sum - siz[x]);
	if(f[x] < f[root]) root = x;
}

void work(int x) {
	calc(x, 0, 1);
	vis[x] = true;
	for(node *i = head[x]; i; i = i->nxt) 
		if(!vis[i->to]) {
			calc(i->to, i->dis, -1);
			sum = siz[i->to];
			root = 0;
			getroot(i->to, 0);
			work(root);
		}
}

int main() {
	n = in(), m = in();
	int x, y, z;
	for(int i = 1; i <= n - 1; i++) {
		x = in(), y = in(), z = in();
		add(x, y, z), add(y, x, z);
	}
	f[0] = n, sum = n;
	getroot(1, 0), work(root);
	while(m --> 0) printf(can[in()]? "AYE
" : "NAY
");
	return 0;
}
原文地址:https://www.cnblogs.com/olinr/p/10206208.html