【学习笔记】虚树

未完成,先扔几个代码。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int tpos[N],head[N],tot=0,d[N];
struct Edge{int u,v,next;}G[N<<1];
inline void addedge(int u,int v){
    if(u==v)return;
    G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
}
namespace T{

int head[N],cnt=0,tot=0,size[N],fa[N],top[N],wson[N];
struct Edge{int u,v,next;}G[N<<1];
inline void addedge(int u,int v){
    G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
    G[++tot].u=v;G[tot].v=u;G[tot].next=head[v];head[v]=tot;
}
inline void dfs1(int u,int f){
    size[u]=1;
    for(int i=head[u];i;i=G[i].next){
        int v=G[i].v;if(v==f)continue;
        d[v]=d[u]+1;fa[v]=u;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[wson[u]])wson[u]=v;
    }
}
inline void dfs2(int u,int tp){
    tpos[u]=++cnt;top[u]=tp;
    if(wson[u])dfs2(wson[u],tp);
    for(int i=head[u];i;i=G[i].next){
        int v=G[i].v;if(v==fa[u]||v==wson[u])continue;
        dfs2(v,v);
    }
}
inline int qlca(int u,int v){
    while(top[u]!=top[v]){
        if(d[top[u]]<d[top[v]])swap(u,v);
        u=fa[top[u]];
    }
    if(d[u]>d[v])swap(u,v);return u;
}

}
inline bool cmp(int x,int y){return tpos[x]<tpos[y];}
int st[N],top=0,vis[N],a[N];
inline void build(){
    int k=read();for(int i=1;i<=k;i++)a[i]=read();
    sort(a+1,a+k+1,cmp);st[++top]=1;
    for(int i=1;i<=k;i++){
        int v=a[i],f=T::qlca(v,st[top]);
        if(f==st[top]){st[++top]=v;continue;}
        while(f==T::qlca(v,st[top-1])){
            addedge(st[top-1],st[top]);top--;f=T::qlca(v,st[top]);
        }
        addedge(f,st[top]);st[top]=f;st[++top]=v;
    }
    while(--top)addedge(st[top],st[top+1]);
}
时间: 2024-12-28 03:59:15

【学习笔记】虚树的相关文章

数据结构学习笔记(树、二叉树)

树(一对多的数据结构) 树(Tree)是n(n>=0)个结点的有限集.n=0时称为空树.在任意一颗非空树种: (1)有且仅有一个特定的称为根(Root)的结点: (2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1.T2........Tn,其中每一个集合本身又是一棵树,并且称为根的子树. 对于树的定义还需要强调两点:1.n>0时根结点是唯一的,不可能存在多个根结点,数据结构中的树只能有一个根结点.2.m>0时,子树的个数没有限制,但它们一定是互不相交的. 结点

[学习笔记]主席树

权值线段树 线段树上每个区间记录的是区间内所有数出现次数的总和. 然后就可以求出整棵线段树的第k大的数了(类似于二叉查找树?) 主席树 建立$n$棵上述的权值线段树,第$i$棵表示$a_1-a_i$的所有数组成的权值线段树. 用可持久化线段树的思想会发现,第$i$棵线段树与第$(i-1)$棵线段树之间只有$logn$个区间值是不同的,所以每次只要新建$logn$个区间,总复杂度是$O(nlogn)$. 区间查询类似于前缀和. 例题 bzoj4408

学习笔记:树分治

树分治用于解决有关路径的问题.树分治分为点分治和边分治(其实还有一种叫“链分治”,是树的路径剖分思想的更高级的体现,一般链分治的题目都可以用路径剖分解决).点分治就是每次找到重心,然后把重心去掉,对分成的每两棵树之间分别统计路径信息(以重心的每个相邻点为根,遍历整棵子树即可得到这个根到每个结点的统计信息),就可以知道包含这个重心的所有路径的信息,然后对于剩下的路径就是在子树里面进行同样的操作了,直到只剩一个点为止(注意这一个点所构成的路径有时也要处理一下).边分治就是每次找到一条边,使得删掉这条

二叉树学习笔记之树的旋转

树旋转(Tree rotation)是二叉树中的一种子树调整操作,每一次旋转并不影响对该二叉树进行中序遍历的结果.树旋转通常应用于需要调整树的局部平衡性的场合. >>左旋和右旋 树的旋转有两种基本的操作,即左旋(逆时针方向旋转)和右旋(顺时针方向旋转). 树旋转包括两个不同的方式,分别是左旋转(以P为转轴)和右旋转(以Q为转轴).两种旋转呈镜像,而且互为逆操作. 下图示意了两种树旋转过程中, 子树的初态和终态 +---+ +---+ | Q | | P | +---+ +---+ / \ ri

数据结构学习笔记04树(二叉树、二叉搜索树、平衡二叉树)

一.树 树的基本术语 ①结点的度(Degree):结点的子树个数 ②树的度:树的所有结点中最大的度数 ③叶结点(Leaf):度为0的结点 ④父结点(Parent):有子树的结点是其子树的根结点的父结点 ⑤子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点:子结点也称孩子结点. ⑥兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点. ⑦路径和路径长度:从结点n1到nk的路径为一个结点序列n1 , n2 ,… , nk , ni是 ni+1的父结点.路径所包含边

数据结构学习笔记04树(堆 哈夫曼树 并查集)

一.堆(heap) 优先队列(Priority Queue):特殊的“队列”,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序. 数组 : 插入 — 元素总是插入尾部 ~ O ( 1 ) 删除 — 查找最大(或最小)关键字 ~ O ( n ) 从数组中删去需要移动元素 ~ O( n ) 链表: 插入 — 元素总是插入链表的头部 ~ O ( 1 ) 删除 — 查找最大(或最小)关键字 ~ O ( n ) 删去结点 ~ O( 1 ) 有序数组: 插入 — 找到合适的位置

C++学习笔记——虚函数

基本概念 虚函数是在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为: virtual 函数返回类型 函数名(参数表) {函数体}: C++中用它来实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数. 虚函数实现机制 虚函数是如何做到因对象的不同而调用其相应的函数的呢? 现在我们就来剖析虚函数.我们先定义两个类 class A{//虚函数示例代码 public: virtual voidfun(){cout<<1<<end

学习笔记::矩阵树定理

我很懒惰,没有理解 是这样做的 先计算每个点的度数 a[i][j]=i到j边数*-1 进行高斯消元 最后把对角线乘起来就是答案 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define eps 1e-9 #define N 20 int n,m; int d[N][N],c[N][N]; double a[N][N];

《Hibernate学习笔记十一》:树状结构设计

<Hibernate学习笔记十一>:树状结构设计 这是马士兵老师讲解Hibernate的一个作业题,树状结构设计,这是一个比较典型的例子,因此有必要写篇博文记录下. 树状结构的设计,它是在同一个类中使用了多对一(ManyToOne)和一对多(OneToMany). 在完成这个题目我们应该按照如下的步骤进行: 1.先思考数据库的模型应该是什么样的?? 数据库中的模型应该如下:即存在id p_id 2.思考面向对象的模型,及如何来进行映射??? 根据数据库中表的特点,对象应该有id name;由于

C++学习笔记--从虚函数说开去

虚函数与纯虚函数: 虚函数:在某基类中声明为virtual并在一个或多个派生类中被重新定义的成员函数,virtual  函数返回类型  函数名(参数表){函数体;} ,实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数.注意虚函数在基类中是有定义的,即便定义是空. 纯虚函数:在基类中是没有定义的,必须由派生类重定义实现,否则不能由对象进行调用. 看下面的例子: #include<iostream> using namespace std; class Cshape { p