首页 > 其他分享 >树分治学习笔记

树分治学习笔记

时间:2023-05-02 20:33:18浏览次数:40  
标签:int text lca 分治 笔记 学习 siz first

前言

既然序列可以分治,那么树也可以分治。树上的分治可以分为点分治与边分治。

点分治

边分治主要用于处理树上路径问题。

考虑一个分治的过程:选中一棵树的根,计算经过根的路径的贡献,然后以其子结点为根对子树递归地计算贡献。容易发现,在构造数据下这种算法的复杂度是可以达到 \(O(n^2)\) 的,原因在于递归的层数可能太深了。如果不使用子结点,而是使用子树的重心,那么每一次子树的大小都会减半,递归层数降到了 \(O(\log n)\) 级别。而每一层的点数是 \(O(n)\) 的,所以总时间复杂度变成了 \(O(nk\log n)\),其中 \(k\) 是统计贡献的复杂度。

然而从理论到实现还是需要一定距离的,因为点分治需要很多细节。贴一份代码,题目是 P3806 【模板】点分治1

code1
#include<bits/stdc++.h>
using namespace std;
const int N=10005,M=105;
int n,m,root,k[M],siz[N];
bool vis[N],keg[N*N],ans[M];
vector<pair<int,int> >G[N];
stack<int>s;
void dfs1(int p,int lst) {//修改子树大小
    siz[p]=1;
    for (auto x:G[p]) {
        if (x.first!=lst&&!vis[x.first]) dfs1(x.first,p),siz[p]+=siz[x.first];
    }
    return;
}
void dfs2(int p,int lst,int sum) {//更新重心
    bool f=1;
    for (auto x:G[p]) {
        if (x.first!=lst&&!vis[x.first]) {
            dfs2(x.first,p,sum);
            if (siz[x.first]*2>sum) f=0;
        }
    }
    if ((sum-siz[p])*2>sum) f=0;
    if (f) root=p;
    return;
}
void dfs3(int p,int lst,int d) {//计算贡献
    s.push(d);
    for (int i=1;i<=m;i++) if (d<=k[i]) ans[i]|=keg[k[i]-d];
    for (auto x:G[p]) {
        if (x.first!=lst&&!vis[x.first]) {
            dfs3(x.first,p,d+x.second);
            if (p==root) {//要注意产生贡献的两个点必须在不同的子树内
                while (!s.empty()) keg[s.top()]=1,s.pop();
            }
        }
    }
    return;
}
void dfs4(int p,int lst,int d) {
    keg[d]=0;//消除贡献(必须逐个撤回,否则复杂度有问题)
    for (auto x:G[p]) {
        if (x.first!=lst&&!vis[x.first]) dfs4(x.first,p,d+x.second);
    }
    return;
}
void dfz(int p) {
    keg[0]=1;
    dfs3(root,0,0);
    dfs4(root,0,0);
    vis[root]=1;//将此节点标记为不可用
    for (auto x:G[root]) {
        if (!vis[x.first]) {
            dfs1(x.first,0);
            dfs2(x.first,0,siz[x.first]);
            dfz(x.first);
        }
    }
    return;
}
int main() {
    scanf("%d %d",&n,&m);
    for (int i=1;i<n;i++) {
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        G[u].push_back({v,w});
        G[v].push_back({u,w});
    }
    for (int i=1;i<=m;i++) scanf("%d",&k[i]);//离线下来处理常数会小一些
    dfs1(1,0);
    dfs2(1,0,n);
    dfz(1);
    for (int i=1;i<=m;i++) {
        if (ans[i]) puts("AYE");
        else puts("NAY");
    }
    return 0;
}

点分树

有了点分治的基础,我们就可以方便定义点分树了。点分树的构造方式就是每一个重心向下一层递归中心连有向边,形成一棵有根树。它有两个重要的性质:

  • 它的深度是 \(O(\log n)\) 级别的。

  • 对于 \(u\) 和 \(v\),它们在点分树上的 \(\text{lca}\) 在原树 \(u\) 到 \(v\) 的路径上。

由第二个性质我们可以得到 \(\text{dist}(u,\text{lca})+\text{dist}(v,\text{lca})=\text{dist}(u,v)\)。其中 \(\text{dist}\) 是原树上距离,而 \(\text{lca}\) 是点分树上 \(\text{lca}\)。

标签:int,text,lca,分治,笔记,学习,siz,first
From: https://www.cnblogs.com/tulipenoire/p/17368230.html

相关文章

  • 平衡树学习笔记
    前置芝士平衡树的前置芝士:全局平衡二叉树。平衡树平衡树是一种基于二叉搜索树的数据结构。满足:左儿子\(<\)根\(<\)右儿子。也就是一切小于根节点的在左边,一切大于根节点的在右边。这样想要查找一个节点的位置时间复杂度就是\(O(\logn)\)。平衡树主要有三种:Splay,Trea......
  • 机器学习算法 随机森林学习 之决策树
    随机森林是基于集体智慧的一个机器学习算法,也是目前最好的机器学习算法之一。随机森林实际是一堆决策树的组合(正如其名,树多了就是森林了)。在用于分类一个新变量时,相关的检测数据提交给构建好的每个分类树。每个树给出一个分类结果,最终选择被最多的分类树支持的分类结果。回归则是不......
  • 【pytorch】土堆pytorch教程学习(四)Transforms 的使用
    transforms在工具包torchvision下,用来对图像进行预处理:数据中心化、数据标准化、缩放、裁剪、旋转、翻转、填充、噪声添加、灰度变换、线性变换、仿射变换、亮度/饱和度/对比度变换等。transforms本质就是一个python文件,相当于一个工具箱,里面包含诸如Resize、ToTensor、Nor......
  • 迁移学习《mixup: Beyond Empirical Risk Minimization》
    论文信息论文标题:mixup:BeyondEmpiricalRiskMinimization论文作者:TakeruMiyato,S.Maeda,MasanoriKoyama,S.Ishii论文来源:2018ICLR论文地址:download 论文代码:download视屏讲解:click ......
  • render学习
    一.前言1.vue程序的运行过程:模板->进行编译->生成ast树->数据绑定->生成render函数->成虚拟dom树->真实dom树模板:Vue的模板基于纯HTML,基于Vue的模板语法,我们可以比较方便地声明数据和UI的关系。AST:AST是AbstractSyntaxTree的简称,俗称‘抽象语法树’它是一种......
  • 代码自测学习
    1.tensor索引[:,0:3,] 代表从0行开始,一共3-0行b=torch.arange(16,dtype=float).reshape(1,4,4)print(b)print(b[:,0:1,]) ......
  • Vue指令学习
    1.指令的定义指令(Directives)是带有 v- 前缀的特殊attribute。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM。指令还有一些基本的要了解的就是指令的修饰符(.native,.stop,.prevent等),动态参数(<a@[event]="doSomething">),缩写(:,@等)。这些都是......
  • 《重构:改善既有代码的设计》学习笔记
    代码的坏味道名称说明重构手法神秘命名MysteriousName好的命名能够节省时间改变函数神秘、变量改名、字段改名重复代码DuplicatedName重复代码让人不得不留意其中的细微差异提炼函数、移动语句、函数上移过长函数LongFunction函数越长,就越难理解提炼函......
  • 迁移学习(VMT)《Virtual Mixup Training for Unsupervised Domain Adaptation》
    论文信息论文标题:VirtualMixupTrainingforUnsupervisedDomainAdaptation论文作者:TakeruMiyato,S.Maeda,MasanoriKoyama,S.Ishii论文来源:2019CVPR论文地址:download 论文代码:download视屏讲解:click   ......
  • 点分治学习笔记
    点分治序列上的操作可以用很多方式维护,线段树树状数组平衡树啥的,但是如果毒瘤出题人把序列搬到了树上,则需要一些奇妙方法。一般有两种(好几种?)方法:树链剖分,把树上路径转化成dfn序上的多段进行操作。LCT,不多说,目前只会板子,没搞太懂。点分治,这个是不用把树转化成序列的,而是将树......