树的分块练习

树的分块一般有以下几种

  • 按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();
}

 

posted @ 2019-03-08 09:45  uid001  阅读(243)  评论(0编辑  收藏  举报