树的分块一般有以下几种
- 按dfs序分块
- 按size分块
- 按深度分块
- 王室联邦分块
练习1 Luogu P2325 [SCOI2005]王室联邦
要求将树分成若干块, 使得每块大小范围在[B,3B], 块可以不连通, 但添一个点(省会)后必须连通
DFS结束时, 将点加入一个集合, 集合大小不够B的话继续向上返回, 否则直接分一个块, 并将当前DFS到的点当做该块的省会, 可以证明最后分的块范围[B,3B-1], 其余块[B,2*B-1]
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
const int N = 1e6+10, INF = 0x3f3f3f3f;
int n, b, sz, cnt;
int s[N], rt[N], no[N];
vector<int> g[N];
void dfs(int x, int fa) {
int t = sz;
for (int y:g[x]) if (y!=fa) {
dfs(y,x);
if (sz-t>=b) {
rt[++cnt] = x;
while (sz>t) no[s[sz--]]=cnt;
}
}
s[++sz] = x;
}
int main() {
scanf("%d%d", &n, &b);
REP(i,2,n) {
int u, v;
scanf("%d%d", &u, &v);
g[u].pb(v),g[v].pb(u);
}
dfs(1,0);
if (!cnt) rt[++cnt] = 1;
while (sz) no[s[sz--]]=cnt;
printf("%d\n", cnt);
REP(i,1,n) printf("%d ",no[i]);
puts("");
REP(i,1,cnt) printf("%d ", rt[i]);
puts("");
}
练习2 hdu 6394
大意: 给定树, 每个节点$i$可以上跳距离$a_i$, 给定$m$个操作, 询问点$i$跳多少次能到根, 修改$a_i$的值.
按深度分块, 本题保证$fa[i]<i$, 分块可以不需要建树
const int N = 1e5+10, M = 450;
int n, m, sqn;
int Log[N], a[N], fa[N][20];
int blo[N], cnt[N], pos[N];
int L[M], R[M];
int get(int x, int k) {
REP(i,0,Log[k]) if (k>>i&1) x=fa[x][i];
return x;
}
void update(int id) {
REP(i,L[id],R[id]) {
if (a[i]<L[id]) {
cnt[i] = 1;
pos[i] = a[i];
}
else {
cnt[i] = cnt[a[i]]+1;
pos[i] = pos[a[i]];
}
}
}
int query(int x) {
int ans = 0;
while (x) ans+=cnt[x],x=pos[x];
return ans;
}
void work() {
scanf("%d", &n);
if (n>100000) for(;;);
REP(i,2,n) scanf("%d", &fa[i][0]);
REP(i,1,Log[n]) REP(j,1,n) fa[j][i]=fa[fa[j][i-1]][i-1];
REP(i,1,n) {
scanf("%d", a+i);
a[i] = get(i,a[i]);
}
sqn = sqrt(n);
REP(i,1,n) blo[i] = (i-1)/sqn+1;
REP(i,1,blo[n]) {
L[i] = (i-1)*sqn+1;
R[i] = i*sqn;
update(i);
}
scanf("%d", &m);
REP(i,1,m) {
int op, x, y;
scanf("%d%d", &op, &x);
if (op==1) printf("%d\n",query(x));
else {
scanf("%d",&y);
a[x] = get(x,y);
update(blo[x]);
}
}
REP(i,0,Log[n]) REP(j,1,n) fa[j][i]=0;
}
int main() {
Log[0]=-1;
REP(i,1,N-1) Log[i]=Log[i>>1]+1;
int T;
scanf("%d", &T);
while (T--) work();
}