点分治入门学习笔记

模板链接 \(Click\) \(Here\)

终于又打开了一个天坑。。。。点分治真的是好东西呢\(QwQ\)

点分治的核心思想在于把问题划分为每一个点可以统计的形式,然后对树上的点进行分治。为了保证复杂度为\(log\),需要每次都找询问子树的重心。

可以很好的解决关于所有链信息的询问。通常离线。

#include <bits/stdc++.h>
using namespace std;

const int M = 110;
const int N = 10010;
const int INF = 10000010;

int n, m, cnt, head[N];

struct edge {
	int nxt, to, w;

	edge (int _nxt = 0, int _to = 0, int _w = 0) {
		nxt = _nxt, to = _to, w = _w;
	}
	
}e[N << 1];

void add_len (int u, int v, int w) {
	e[++cnt] = edge (head[u], v, w); head[u] = cnt;
	e[++cnt] = edge (head[v], u, w); head[v] = cnt;
}

int rt, sum, sz[N], qry[M], rem[N], res[M], dis[N], maxp[N];

bool vis[N], have[INF];

void get_root (int u, int fa) {
	sz[u] = 1, maxp[u] = 0;
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa && !vis[v]) { //vis 限制只访问这棵子树的信息。
			get_root (v, u);
			sz[u] += sz[v];
			maxp[u] = max (maxp[u], sz[v]);
		}
	}
	maxp[u] = max (maxp[u], sum - sz[u]); //sum 是当前子树大小
	if (maxp[u] < maxp[rt]) rt = u;
}

void get_dis (int u, int fa) {
	rem[++rem[0]] = dis[u];
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (!vis[v] && v != fa) {
			dis[v] = dis[u] + e[i].w;
			get_dis (v, u);
		}
	}
}

queue <int> q;

void calc (int u) {
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (!vis[v]) {
			rem[0] = 0, dis[v] = e[i].w;
			get_dis (v, u);
			for (int j = 1; j <= rem[0]; ++j) {
				for (int k = 1; k <= m; ++k) {
					if (qry[k] >= rem[j]) {
						res[k] |= have[qry[k] - rem[j]];
					}
				}
			}
			for (int j = 1; j <= rem[0]; ++j) {
				q.push (rem[j]); have[rem[j]] = true;
			}
		}
	}
	while (!q.empty ()) have[q.front ()] = false, q.pop ();
}

void solve (int u) {
	//have[i] -> 是否存在 dis = i 的路径
	vis[u] = have[0] = true; calc (u);
	//只能访问 u 的子树, 计算 u 子树的状态
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (!vis[v]) {
			sum = sz[v];
			maxp[rt = 0] = INF;
			get_root (v, 0);
			solve (rt);
		}
	}
}

int main () {
	cin >> n >> m;
	for (int i = 1; i <= n - 1; ++i) {
		static int u, v, w;
		cin >> u >> v >> w;
		add_len (u, v, w);
	}
	for (int i = 1; i <= m; ++i) cin >> qry[i];
	maxp[rt] = sum = n;
	get_root (1, 0);
	solve (rt);
	for (int i = 1; i <= m; ++i) {
		puts (res[i] ? "AYE" : "NAY");
	}
} 

posted @ 2019-03-12 11:36  maomao9173  阅读(106)  评论(0编辑  收藏  举报