首页 > 编程语言 >【算法专题】分治

【算法专题】分治

时间:2022-12-28 17:47:37浏览次数:60  
标签:子树 重心 idx int 分治 maxSize 算法 专题

【算法专题】分治

点分治与点分树

https://oi-wiki.org/graph/tree-divide/

点分治:
按重心划分子树。

  1. 在子树内部处理
  2. 归并子树

AcWing 252. 树

https://www.acwing.com/problem/content/254/

  1. 两点在同一子树内
  2. 某点是重心
  3. 两点不在同一子树内,路径经过重心(容斥删去不合法路径

等价于给一堆数,任取两个数总和小于等于k的方案数是多少。
(重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。)

代码:嗨多细节

#include <bits/stdc++.h>

using namespace std;
const int N = 1e4 + 5, M = N * 2;
int h[N], e[M], ne[M], w[M], idx;
bool vis[N]; //该点是否被删
int dis_all[N], dis_cur[N]; //重心到所有子树的距离,重心到当前子树的距离
int n, m;

void add (int a, int b, int c) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

int getSize (int u, int fa) { //以u为根的子树大小
    if (vis[u])     return 0; 
    int sz = 1;
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (j == fa)    continue;
        sz += getSize (j, u);
    }
    return sz;
}

int getCenter (int u, int fa, int allSize, int &ct) { //求重心
    if (vis[u])     return 0;
    int sum = 1, maxSize = 1; //u的子树的结点个数
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (j == fa)    continue;
        int curSize = getCenter (j, u, allSize, ct);
        sum += curSize;
        maxSize = max (maxSize, curSize);
    }
    maxSize = max (maxSize, allSize - sum);
    if (maxSize <= allSize / 2)   ct = u; //不一定是重心,满足一半即可,保证logn
    return sum;
}

void getDis (int u, int fa, int dis, int &len) { //当前子树上所有点到根的距离
    if (vis[u])     return ;
    dis_cur[len++] = dis;
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (j == fa)    continue;
        getDis (j, u, dis + w[i], len); //dis + w[i]记得更新距离啊!!
    }
}

int count (int *a, int sz) { //a[]中选两点满足dis<=m
    sort (a, a + sz);
    int cnt = 0; //满足条件的点对个数
    for (int i = sz - 1, j = -1; i >= 0; i--) {
        while (j < i - 1 && a[i] + a[j + 1] <= m)   j++;
        j = min (j, i - 1); //j左i右
        cnt += j + 1;
    }
    return cnt;
}

int cal (int u) { //递归计算以u为根的答案
    if (vis[u])     return 0;
    getCenter (u, -1, getSize (u, -1), u);
    vis[u] = true; //删重心

    int len = 0, cnt = 0;
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        int len_cur = 0; //当前子树大小
        getDis (j, -1, w[i], len_cur);
        cnt -= count (dis_cur, len_cur); //情况3: 容斥掉同一树内的点对

        for (int k = 0; k < len_cur; k++) {
            if (dis_cur[k] <= m)    cnt++; //情况2: 某点是重心
            dis_all[len++] = dis_cur[k];
        }
    }
    cnt += count (dis_all, len); //情况3: 不同子树间的点对
    for (int i = h[u]; ~i; i = ne[i])    cnt += cal (e[i]);
    return cnt;
}

int main () {
    while (cin >> n >> m, n || m) {
        memset (h, -1, sizeof h), idx = 0;
        memset (vis, false, sizeof vis);
        for (int i = 1; i < n; i++) {
            int a, b, c;
            cin >> a >> b >> c;
            add (a, b, c), add (b, a, c);
        }
        cout << cal (0) << endl;
    }
}

边分治

CDQ分治

标签:子树,重心,idx,int,分治,maxSize,算法,专题
From: https://www.cnblogs.com/CTing/p/17010259.html

相关文章

  • 数据结构的算法度量方法
    1.时间复杂度1.时间复杂度是衡量一个算法运行所需的时间,是一个函数,由于执行时间需要经过测试才能得出,而算法执行的时间和执行次数成正比例关系,所以我们的时间复杂度根......
  • MySQL索引背后的数据结构及算法原理
     摘要本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题。特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多......
  • PCFG中inside和outside算法详解
    outside值要分为两部分计算:......
  • 每日算法之剪绳子
    JZ14剪绳子描述给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],...,k[m]。请问k[1]*k[2]*........
  • 每日算法之求1+2+3+...+n
    JZ64求1+2+3+...+n题目求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。方法位运算思路算法实现从1连加到n,......
  • m认知无线电信号检测算法matlab仿真,能量检测,循环平稳检测以及自相关检测
    1.算法概述频谱感测是认知无线电的一项关键技术。我们将频谱感知作为一个分类问题,提出一种基于深度学习分类的感知方法。我们归一化接收信号功率以克服噪声功率不确定性的......
  • m认知无线电信号检测算法matlab仿真,能量检测,循环平稳检测以及自相关检测
    1.算法概述      频谱感测是认知无线电的一项关键技术。我们将频谱感知作为一个分类问题,提出一种基于深度学习分类的感知方法。我们归一化接收信号功率以克服噪声功......
  • Java实现操作系统的银行家算法详解
      一、目的  通过编写一个模拟动态资源分配的银行家算法程序,进一步深入理解死锁、产生死锁的必要条件、安全状态等重要概念,并掌握避免死锁的具体实施方法。二......
  • 解密随机数生成器(二)——从java源码看线性同余算法
    RandomJava中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linearcongruentialformula线性同余方程(DonaldKnuth的编程艺术的3.2.1节)如果两个Random实例使......
  • visual hull算法的原理和仿真概述
    Visual-Hull+Bregman迭代      这个部分,算法,主要是实现一下效果,这里增加了迭代过程。具体原理如下所示:       这个迭代算法的作用就是通过不断的迭代,使其......