之前diaoye的一道题是要用点分治写..但是我省选前临时学的点分治,当时又只打了几个板子,中间又没有写过有关的题,于是现在就似乎不太会了,刚好昨天又讲了,今天就复习一下
引用讲课 PPT P P T 里的一段话
点分治,是处理树上路径/连通块的一种常见算法。
这一类问题有时可以通过lca来处理,但是有的时候复杂度会略高。
点分治,每次对当前的树求出重心,处理所有经过重心的路径/连通块,然后递归每个子树。
这样,每个节点只会出现在log次分治中。
然后点分治我觉得可能也是跟容斥有关的,因为它主要思想还是先计算不考虑限制的答案再减去包含限制的答案,然后比较重要的地方就是每次都以树的重心为根来进行分治处理。
update:看来自己还是对这个算法理解不够… 感谢
ylsoijulao
y
l
s
o
i
j
u
l
a
o
的讲解
就是有一些细节地方还是需要注意 第一个就是每次分治对于每棵子树又要重新确定重心,这我原来是没有做的…重新确定重心后那么子树的
size
s
i
z
e
又会改变, 所以每次处理一棵子树的时候又要重新记一次
size
s
i
z
e
直接上例题吧
https://www.luogu.org/problemnew/show/P4178
luogu4178 Tree
裸题,直接上板子即可
#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
using namespace std;
const int maxn = 40000 + 10;
int to[maxn << 1], head[maxn], nxt[maxn << 1], v[maxn << 1], e;
int all, n, root, size[maxn], sizemax[maxn], ans;
int now[maxn], dep[maxn], k, vis[maxn];
void add(int x, int y, int z) {
to[++ e] = y;
nxt[e] = head[x];
head[x] = e;
v[e] = z;
}
void get_dep(int x, int fa) {
now[++ now[0]] = dep[x];
go(x, i)
if(!vis[to[i]] && to[i] != fa) {
dep[to[i]] = dep[x] + v[i];
get_dep(to[i], x);
}
}
int cal(int x, int From) {
now[0] = 0, dep[x] = From;
get_dep(x, 0); sort(now + 1, now + now[0] + 1);
int l = 1, r = now[0], res = 0;
while(l < r)
if(now[l] + now[r] <= k)
res += r - l, ++ l;
else
-- r;
return res;
}
void get_root(int x, int fa) {
size[x] = 1, sizemax[x] = INT_MIN;
go(x, i)
if(!vis[to[i]] && to[i] != fa) {
get_root(to[i], x);
size[x] += size[to[i]];
if(size[to[i]] > sizemax[x])
sizemax[x] = size[to[i]];
}
if(all - size[x] > sizemax[x])
sizemax[x] = all - size[x];
if(sizemax[root] > sizemax[x])
root = x;
}
void solve(int x) {
vis[x] = 1, get_root(x, 0);
ans += cal(x, 0);
go(x, i)
if(!vis[to[i]]) {
ans -= cal(to[i], v[i]);
all = size[x], root = 0;
get_root(to[i], x);
solve(root);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("4178.in", "r", stdin);
freopen("4178.out", "w", stdout);
#endif
int x, y, z;
scanf("%d", &n);
For(i, 1, n - 1) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z), add(y, x, z);
}
all = n, sizemax[0] = INT_MAX;
get_root(1, 0), scanf("%d", &k);
solve(root); printf("%d\n", ans);
return 0;
}