分治学习指南
典题合集
前置芝士
点分治
适合处理大规模树上路径信息问题
树上路径分为:1.经过根节点的路径。2.不经过根节点的路径
[step]
(1)找到树的重心做根,getroot()
(2)求出子树中的各点到根的距离,getdis()
(3)对当前树统计答案,calc()
(4)分治各个子树,重复以上操作,divide()
树上距离为k的点对
[problem description]
给定一棵有 \(n\) 个点的树,询问树上距离为 \(k\) 的点对是否存在。
[input]
第一行两个数 \(n,m\)。
第 \(2\) 到第 \(n\) 行,每行三个整数 \(u, v, w\),代表树上存在一条连接 \(u\) 和 \(v\) 边权为 \(w\) 的路径。
接下来 \(m\) 行,每行一个整数 \(k\),代表一次询问。
[output]
对于每次询问输出一行一个字符串代表答案,存在输出 AYE
,否则输出 NAY
。
[a.in]
2 1
1 2 2
2
[a.out]
AYE
[datas]
\(1 \leq n\leq 10^4\),\(1 \leq m\leq 100\),\(1 \leq k \leq 10^7\),\(1 \leq u, v \leq n\),\(1 \leq w \leq 10^4\)
[solved]
const int N = 10010;
const int INF = 10000010;
struct edge {
int v, w, ne;
} e[N * 2];
int h[N], idx;
int del[N], sz[N], mxs, sum, root;
int dis[N], d[N], cnt;
int ans[N], q[INF], judge[INF];
int n, m, ask[N];
void add(int u, int v, int w) {
e[++idx] = {v, w, h[u]};
h[u] = idx;
}
//寻找重心
void getroot(int u, int fa) {
sz[u] = 1;
int s = 0;
for (int i = h[u]; i; i = e[i].ne) {
int v = e[i].v;
if (v == fa || del[v]) continue;
getroot(v, u);
sz[u] += sz[v];
s = max(s, sz[v]);
}
s = max(s, sum - sz[u]);
if (s < mxs) mxs = s, root = u;
}
//记录各个点到根节点的距离
void getdis(int u, int fa) {
dis[++cnt] = d[u];
for (int i = h[u]; i; i = e[i].ne) {
int v = e[i].v;
if (v == fa || del[v]) continue;
d[v] = d[u] + e[i].w;
getdis(v, u);
}
}
void calc(int u) {
del[u] = judge[0] = 1;
int p = 0;
for (int i = h[u]; i; i = e[i].ne) {
int v = e[i].v;
if (del[v]) continue;
cnt = 0;
d[v] = e[i].w;
//求出子树v的各点到u的距离
getdis(v, u);
for (int j = 1; j <= cnt; j++) {
for (int k = 1; k <= m; k++) {
if (ask[k] >= dis[j])
ans[k] |= judge[ask[k] - dis[j]];
}
}
//记录合法路径
for (int j = 1; j <= cnt; j++) {
if (dis[j] < INF)
q[++p] = dis[j], judge[dis[j]] = 1;
}
}
for (int i = 1; i <= p; i++) judge[q[i]] = 0;
}
void divide(int u) {
calc(u);
for (int i = h[u]; i; i = e[i].ne) {
int v = e[i].v;
if (del[v]) continue;
mxs = sum = sz[v];
getroot(v, 0);
divide(root);
}
}
void solve() {
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
cin >> n >> m;
for (int i = 1, x, y, w; i < n; i++) {
cin >> x >> y >> w;
add(x, y, w);
add(y, x, w);
}
for (int i = 1; i <= m; i++) {
cin >> ask[i];
}
mxs=sum=n;
getroot(1,0);
getroot(root,0);
divide(root);
for (int i = 1; i <= m; i++) {
if (ans[i])cout << "AYE" << endl;
else cout<<"NAY"<<endl;
}
}