树的分块练习
树的分块一般有以下几种
- 按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(); }