zoukankan      html  css  js  c++  java
  • 树的分块练习

    树的分块一般有以下几种

    • 按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
    ", 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
    ",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();
    }
    
  • 相关阅读:
    常见面试测试要点
    怎样在 CentOS/RHEL 7/6 上安装和配置 Sendmail 服务器
    Cannot uninstall 'pyparsing'. It is a distutils installed project
    Linux下校验SHA1和MD5的方法
    Linux查看进程启动时间和运行多长时间
    sqlplus -S参数表示什么意思?
    dnspython模块报错 AttributeError: 'CNAME' object has no attribute 'address'
    CentOS7中安装pip的方法
    四则运算中遇到的一个问题
    动手动脑
  • 原文地址:https://www.cnblogs.com/uid001/p/10420571.html
Copyright © 2011-2022 走看看