全局平衡二叉树 P4751 【模板】“动态DP“

全局平衡二叉树 全局平衡二叉树 类似于静态的 LCT? 建树方法: 先树剖,考虑对于每一条重链维护一棵二叉树,且每条重链的二叉树的根与该重链的链头的父亲之间有一条虚边(认父不认子)。 为了达到全局的平衡,每棵重链的二叉树并不是完美的二叉树:对于该重链上的每个点 uuu 设置一个权值 vuv_uvu​ 为该点的轻子树大小和 +1+1+1(即 sz[u]−sz[son[u]]sz[u]-sz[son[u]]sz[u]−sz[son[u]]),然后找到这条链上的带权中点作为这棵二叉树的根(即找到一个位置 kkk 使得 sk−1≤ 阅读详情

全局平衡二叉树 P4751 【模板】"动态DP"

P4751 【模板】“动态DP”&动态树分治(加强版)

有事没事就用 v e c t o r \tt vector vector 总会有天废掉的。

注意在 c + + 11 \tt c++11 c++11 之后 v e c t o r \tt vector vector 不管是是否在 O 2 O2 O2 的条件下,速度都比常规数组慢很多,甚至比链表要慢 4 4 4 倍。

死亡写法:

struct Tree : vector<vector<int>> {
    Tree() : vector<vector<int>>(2, vector<int>(2, -inf)) {}
    Tree operator * (const Tree &z) {
        Tree res;
        for(int i = 0; i < 2; ++ i) for(int j = 0; j < 2; ++ j) for(int k = 0; k < 2; ++ k)
            res[i][j] = max(res[i][j], this->at(i)[k] + z[k][j]);
        return res;
    }
};

要是闲着搞类继承没救了。


发现树剖有两个 $\log $ 我们发现 L C T \tt LCT LCT 只有一个 log ⁡ \log log 但是这个常数确实有点大。

因为树是静态的,我们直接树链剖分之后建立一个静态的 B s t \tt Bst Bst 即可。

至于具体的形态其实和 L C T \tt LCT LCT 是一样的,只是我们每次当做根节点的都是带权重心,权值是轻子树大小。

之后转移的方法还是和树链剖分一样,但是这里需要维护两个数组,因为不能每次都直接像线段树一样从下到上进行转移,也就是对于每一个点特殊保留一个轻儿子的矩阵。

可以发现对于全局来说这个树是联通的而且最深处也只有 log ⁡ n \log n logn。那么我们直接暴力跳父亲进行合并复杂度就是一个 $\log $ 的。

顺便说一下定义:

  • f ( i , 0 / 1 ) f(i, 0/ 1) f(i,0/1) 对于当前子树,当前点是否选择的最大权值。
  • g ( i , 0 / 1 ) g(i, 0/1) g(i,0/1) 对于当前轻儿子,当前点是否选择的最大权值。
  • a ( i ) a(i) a(i) 点权。
  • l s i z ( i ) lsiz(i) lsiz(i) 点 i i i 轻儿子大小。

不妨设 v v v 的父亲是 u u u, v , u v, u v,u 在同一条重链上,矩阵转移方程:
[ f ( v , 0 ) f ( v , 1 ) ] × [ g ( u , 0 ) g ( u , 1 ) + a ( u ) g ( u , 0 ) − ∞ ] \left[ \begin{matrix} f(v, 0) & f(v, 1) \end{matrix} \right] \times \left[ \begin{matrix} g(u, 0) & g(u, 1) + a(u) \\ g(u, 0) & - \infty \end{matrix} \right] [f(v,0)​f(v,1)​]×[g(u,0)g(u,0)​g(u,1)+a(u)−∞​]

#include <bits/stdc++.h>
using namespace std;

#define Fread
//#define Getmod

#ifdef Fread
char buf[1 << 21], *iS, *iT;
#define gc() (iS == iT ? (iT = (iS = buf) + fread (buf, 1, 1 << 21, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
#define getchar gc
#endif // Fread

template <typename T>
void r1(T &x) {
	x = 0;
	char c(getchar());
	int f(1);
	for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);
	x *= f;
}

template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
    r1(t);  r1(args...);
}

//#define int long long
const int maxn = 1e6 + 5;
const int maxm = maxn << 1;

int head[maxn], cnt;
struct Edge {
    int to, next;
}edg[maxn << 1];
void add(int u,int v) {
    edg[++ cnt] = (Edge) {v, head[u]}, head[u] = cnt;
}
int a[maxn];
int n, m;

#define max Max
inline int Max(const int& a, const int& b) { return a > b ? a : b; }
const int inf = 0x3f3f3f3f;
struct Tree {
    int a[2][2];
    Tree(void) { memset(a, -0x3f, sizeof(a)); }
    int* operator [] (const int& x) { return a[x]; }
    const int* operator [] (const int&x) const { return a[x]; }
    Tree operator * (const Tree &z) {
        Tree res;
        for(int i = 0; i < 2; ++ i) for(int j = 0; j < 2; ++ j) for(int k = 0; k < 2; ++ k)
            res[i][j] = max(res[i][j], a[i][k] + z[k][j]);
        return res;
    }
};

int f[maxn][2], g[maxn][2];
int son[maxn], siz[maxn], lsiz[maxn];
void dfs(int p,int pre) {
    siz[p] = 1;
    for(int i = head[p];i;i = edg[i].next) {
        int v = edg[i].to; if(v == pre) continue;
        dfs(v, p), siz[p] += siz[v];
        if(siz[v] > siz[son[p]]) son[p] = v;
    }
    lsiz[p] = siz[p] - siz[son[p]];
}

void dfs1(int p,int pre) {
    f[p][1] = g[p][1] = a[p];
    f[p][0] = g[p][0] = 0;
    if(son[p]) {
        dfs1(son[p], p),
        f[p][0] += max(f[son[p]][0], f[son[p]][1]),
        f[p][1] += f[son[p]][0];
    }
    else return ;
    for(int i = head[p];i;i = edg[i].next) {
        int v = edg[i].to; if(v == pre || v == son[p]) continue;
        dfs1(v, p),
        f[p][0] += max(f[v][0], f[v][1]),
        g[p][0] += max(f[v][0], f[v][1]),
        f[p][1] += f[v][0], g[p][1] += f[v][0];
    }
}

int fa[maxn], vis[maxn];
int st[maxn];
int sn[maxn][2];
Tree v[maxn], vy[maxn];

void pushup(int p) {
    v[p] = vy[p];
    if(sn[p][0])
        v[p] = v[p] * v[sn[p][0]];
    if(sn[p][1])
        v[p] = v[sn[p][1]] * v[p];
}

int Sbuild(int l,int r) {
//    printf("l = %d, r = %d\n", l, r);
    if(l > r) return 0;
    int tot(0);
    for(int i = l; i <= r; ++ i) tot += lsiz[st[i]];
    for(int i = l, sum(lsiz[st[l]]); i <= r; ++ i, sum += lsiz[st[i]]) if((sum << 1) >= tot) {
        int L = Sbuild(l, i - 1), R = Sbuild(i + 1, r);
        sn[st[i]][0] = L, sn[st[i]][1] = R;
        fa[L] = fa[R] = st[i];
        pushup(st[i]);
        return st[i];
    }
    return 0;
}

int build(int p) {
    for(int u = p; u; u = son[u]) vis[u] = 1;
    for(int u = p, ret; u; u = son[u]) {
        for(int i = head[u];i;i = edg[i].next) {
            int v = edg[i].to; if(vis[v]) continue;
            ret = build(v);
            fa[ret] = u;
        }
    }
    int tot(0);
    for(int u = p; u; u = son[u]) st[++ tot] = u;
    int ret = Sbuild(1, tot);
    return ret;
}

inline int getmx0(const int& p) {
    return max(v[p][0][0], v[p][1][0]);
}

inline int getmx1(const int& p) {
    return v[p][0][1];
}

void Modify(int u, int c) {
    vy[u][0][1] -= a[u] - c; a[u] = c;
    for(int f; f = fa[u], u; u = fa[u]) if(f && u != sn[f][0] && u != sn[f][1]) {
        vy[f][0][0] -= max(getmx1(u), getmx0(u));
        vy[f][1][0] = vy[f][0][0];
        vy[f][0][1] -= getmx0(u);
        pushup(u);
        vy[f][0][0] += max(getmx1(u), getmx0(u));
        vy[f][1][0] = vy[f][0][0];
        vy[f][0][1] += getmx0(u);

    } // light
    else pushup(u);
}

int root;

signed main() {
//    freopen("P4719_5.in", "r", stdin);
//    freopen("S.out", "w", stdout);
    int i, j;
    r1(n, m);
    for(i = 1; i <= n; ++ i) r1(a[i]);
    for(i = 1; i < n; ++ i) {
        int u, v; r1(u, v), add(u, v), add(v, u);
    }
    dfs(1, 0), dfs1(1, 0);
    for(i = 1; i <= n; ++ i) {
        vy[i][1][0] = vy[i][0][0] = g[i][0];
        vy[i][0][1] = g[i][1];
        vy[i][1][1] = -inf;
    }
    root = build(1);
    int lastans(0);
//    printf("rt = %d\n", root);
//    for(i = 1; i <= n; ++ i) printf("%d : %d\n", i, vis[i]);
//    for(i = 1; i <= n; ++ i) printf("%d : %d %d\n", i, ls[i], rs[i]);
//    for(i = 1; i <= n; ++ i) printf("%d : %d\n", i, fa[i]);
//    printf("res = %d, %d\n", Ask(), max(f[1][0], f[1][1]));
    while(m --) {
        int x, y;
        r1(x, y);
        x ^= lastans;
        Modify(x, y);
        printf("%d\n", lastans = max(getmx0(root), getmx1(root)));
    }
	return 0;
}
【数据结构】平衡二叉树 本文主要介绍了平衡二叉树的基本概念及基础操作(查找、平衡、插入、删除)。 阅读详情

相关推荐

DAZ STUDIO 快速渲染技巧

DAZ STUDIO 快速渲染技巧: 本文将向您展示几个快速渲染技巧。您将学习如何使您的Daz Iray渲染和照明在Daz工作室内更快。 当你有一个大场景,这可能需要很多小时进行渲染。 但是如果你想大幅度降低渲染时间呢?这篇文章的提示应该能让你达到这个目标。 首先,我们需要弄清楚一件事——没有“完美的环境或设置”这样的东西。是因为渲染设置是高度个性化和主观性的东西,这主要取决于场景和硬件。如果你有一个功能强大的计算机,你可以允许更多的低渲染时间,反之亦然。因此,一切都取决于您尝试渲染的对象和机器。

DAZSTUDIO的博客 9646

模板:全局平衡二叉树

全局平衡二叉树

BUG_Creater_jie的博客 786

FPGA实战:基于Basys3的多功能数字钟设计与实现

本文详细介绍了基于Basys3开发板的多功能数字钟设计与实现过程,涵盖FPGA开发、SystemVerilog编程及7段数码管驱动等关键技术。通过模块化设计实现时钟分频、时间计数、按键处理等功能,并提供了优化显示驱动和调试技巧,帮助开发者快速掌握数字电路设计核心概念。

weixin_29186249的博客 659

全局平衡二叉树学习笔记

感觉是树剖和lct的一种结合,把树剖的log^2变成log,把lct的常数变小,但是能维护的东西也有局限性... 实际上就是有时候维护的东西不需要lct的link-cut操作,所以可以将树建成一棵棵二叉平衡树连在一起而不需要splay。具体建法就是先轻重链剖分,对每条重链建一棵bst,然后这棵bst的根通过虚边连向这棵bst内深度最浅的点在原树中的父亲。而对于每条重链建bst时,注意为了保证平衡...

caoyang1123的博客 958

Zynq工程IP核封装:XCI引用与约束继承实战指南

IP核封装是FPGA系统设计中实现模块复用、团队协作与技术资产沉淀的关键环节。其本质是将功能逻辑、时序约束、接口协议和硬件配置统一抽象为可配置、可验证、可演进的标准化组件。核心原理在于通过XCI文件保留IP核的参数化定义能力,依托Vivado IP Packager实现约束继承、端口自动映射与时钟域解耦,从而保障跨项目集成的时序可信性与约束完备性。该技术广泛应用于Zynq SoC视频处理、高速接口(如HDMI/TMDS)、多时钟域控制系统等场景,尤其在需要长期维护与版本迭代的工业级嵌入式开发中具有不可替代的

weixin_42593701的博客 123

BQ25798双电源输入4节电池升降压充电与最大功率跟踪于光伏板应用

介绍一颗具有窄范围直流电压NVDC、路径管理PPMT、光伏板最大功率跟踪及反向放电OTG升降压充电控制器,带I2C接口能对内部寄存器做控制

linkedin_38804946的博客 1677

【luogu P4751】【模板】“动态DP“&动态树分治(加强版)(全局平衡二叉树)

给你一棵树,点带权,每次操作修改点权,要你求最大权独立集的权值大小。

欢迎您的光顾awa 284

本地大模型5:在pycharm用python调用ollama本地大模型

python调用ollama本地大模型

weixin_74825941的博客 8377

【题解】P4751 【模板】动态 DP(加强版)(Global Balanced Binary Tree)

全局平衡二叉树版本的动态 DP。

Isaac Regulus的博客 282

数据分析:蛋白质组的GO term的富集分析详解

在获取差异表达蛋白质的数据之后,依据蛋白质与基因的对应映射关系,开展GO(Gene Ontology)term的富集分析。通过这一分析流程,能够精准地识别出不同实验组中过表达基因所关联的显著富集的GO term通路。这些富集的GO term通路为后续的生物学研究提供了关键线索,有助于深入探究基因功能、揭示潜在的生物学机制,从而推动生物学发现的进程。

专注生信领域 1368

CPD (Coherent Point Drift) 算法实现点云配准 C++版

作为和icp并列的点集配准算法cpd为什么没有icp火,等我把整个方案跑完才明白。 首先下载cpd https://github.com/gadomski/cpd 包含的fgt https://github.com/gadomski/fgt 下载到win10的解压后 运行cmake来进行编译 这个时候会提醒缺少eigen3 fgt python 这几个都安装排除后 在build文件夹下会生成vs2017的源码,右键全部生成后在 .\cpd-master\build\Debug 下会生成一个cpd.li

uranus1992的博客 3510

动态DP之全局平衡二叉树

目录 前置知识 全局平衡二叉树 大致介绍 建图过程 修改过程 询问过程 时间复杂度的证明 板题 前置知识 在学习如何使用全局平衡二叉树之前,你首先要知道如何使用树链剖分解决动态DP问题。...

weixin_34044273的博客 289

《QGIS快速入门与应用基础》209:重叠标注处理(移除/偏移)

系统讲解了QGIS中处理标注重叠问题的核心方法与实操流程。文章首先阐述了重叠标注处理的底层逻辑,即 先预防、再调整、后兜底 的递进式策略,并详细介绍了设置入口与界面布局。重点讲解了偏移处理这一首选方案,包括基础方向设置、最大偏移距离与步长配置、以及自动换行等进阶优化规则。针对不同要素类型(点、线、面)提供了行业规范的偏移方向设置建议,并给出从稀疏到密集场景的完整参数推荐值。最后以城市POI点图层为例,演示了5步偏移设置流程,帮助用户实现 无重叠、无压盖、重点突出 的专业标注效果。

LuckyHanMo的博客 671

平衡二叉树(Balanced Binary Tree)

平衡二叉树(Balanced Binary Tree) 平衡二叉树(Balanced Binary Tree)又称AVL树。AVL 树得名于它的发明者 G. M. Adelson-Velsky 和 Evgenii Landis,他们在1962年的论文《An algorithm for the organization of information》中公开了这一数据结构。这种结构完成一系列集合操作时,时间复杂度与空间复杂度比其他树要低,一系列操作始终保存平衡!为大型数据库的组织、索引提供了一条全新的的道路!

laizhenghua的博客 3356

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

数据结构之——平衡二叉树(内容详解)

一、基本概念 平衡二叉树也叫AVL树,它或者是一颗空树,或者具有以下性质的二叉排序树:它的左子树和左子树的高度之差(平衡因子)的绝对值不超过1,且它的左子树和右子树都是一颗平衡二叉树。 二、结构 如基本概念所树,它具有一个左子树和一个左子树,且对于任意一个子树而言,左子树和右子树高度只差不超过1. 2.1 平衡二叉树判别 如下有3棵树,分别判断下哪个是平衡二叉树? 图1: 图2:...

m0_37914588的博客 11万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【总结】动态DP&全局平衡二叉树

前言: 本算法是树剖DDP算法的加速版,复杂度更小(不是特意卡树剖其实看不出来), 但还是比较好写,因此在这里提一下 动态DP 动态DP听起来很黑科技,但其实并不难 首先,能动态的DP本身就很少,需要满足很多限制 而且一般动态DP的题都会给普通DP留部分分,如果有暴力写得好的,甚至可以在低风险下拿到和DDP差不多的分。 扯回正题,动态DP就是把常规DP的转移用矩阵(其实不一定是矩阵,用数据结构特...

氧化钠的博客 618

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【洛谷P4719】动态DP(全局平衡二叉树)

题目大意 给定一棵n个点的树,点带点权。 有m次操作,每次操作给定x,y,表示修改点x的权值为y。 你需要在每次操作之后求出这棵树的最大权独立集的权值大小。 题解 如果不带修改操作,正常的DP式: dp[u][1]dp[u][1]dp[u][1]表示当前结点保证选择,这个结点的子树独立集最大权值。 dp[u][0]dp[u][0]dp[u][0]表示当前结点不选择,这个结点的子树独立集最大权值。 ...

CaptainChen的博客 716

DP也要搞动态,动态DP与全局平衡二叉树详(lue)解

文章目录参考文献术语例题思路全局平衡二叉树代码与细节问题1问题2 该来的还是来了,我是真的不想写这个狗博客,是真的烦。 参考文献 很详细:https://www.luogu.com.cn/blog/ShadowassIIXVIIIIV/solution-p4643 ZFY:抄袭文献 术语 u.lightsonu.lightsonu.lightson,uuu的轻儿子。u.heavysonu.heav...

蒟蒻QMQ 450

01数据结构-平衡二叉树

前面我们介绍了二叉查找树,假设我们最开始送进去的序列就是有序的,那么会造成树往一边倒,如图1,树退化成了单链表,此时查找效率跟我们没有树的时候效率是一样的。那怎么在二叉搜索树的基础上让我们的高度可控,这就是我们今天增加的约束,增加完这个约束后就是我们今天讲的二叉平衡树。图1。

2302_82136376的博客 1107

数据结构之平衡二叉树(AVL树,左旋转,右旋转,双向旋转)

引入:看一下案例(说明二叉排序树可能存在的问题) 数列{1,2,3,4,5,6},二叉排序树(BST)的形式为 平衡二叉树基本介绍 (1)平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree),又被称为AVL树,可以保证查询效率比较高. (2)具有以下特点 ...

qq_44962429的博客 1611

平衡二叉树

1.定义 平衡二叉树,又称AVL树,用于解决二叉排序树高度不确定的情况,如果二叉排序树的子树间的高度相差太大,就会让二叉排序树操作的时间复杂度升级为O(n),为了避免这一情况,为最坏的情况做准备,就出现了平衡二叉树,使树的高度尽可能的小,其本质还是一棵二叉搜索树。 平衡二叉树的性质: 左子树和右子树的高度之差的绝对值小于等于1 左子树和右子树也是平衡二叉树 为了方便起见,给树上的每个结点附加一个数字,给出该结点左子树与右子树的高度差,这个数字称为结点的平衡因子(BF) 平衡因子=结点左子树的高度-

清风 4万+

数据结构(三)—— 树(6):平衡二叉树

6. 平衡二叉树6.1 什么是平衡二叉树6.2 平衡二叉树的调整6.2.1 RR旋转6.2.2 LL旋转6.2.3 LR旋转6.2.4 RL旋转 6. 平衡二叉树 6.1 什么是平衡二叉树   平衡二叉树一般指平衡树。平衡树(Balance Tree,BT) 指的是,任意节点的子树的高度差都小于等于1。常见的符合平衡树的有B树(多路平衡搜索树)、AVL树(二叉平衡搜索树)等。平衡树可以完成集合的一系列操作,时间复杂度和空间复杂度相对于“2-3树”要低,在完成集合的一系列操作中始终保持平衡,为大型数据库的组.

大彤小忆的博客 3298

数据结构:二叉平衡树

数据结构:二叉平衡树

2301_80219163的博客 977

平衡二叉树(AVL)

一、平衡二叉树的引入 看一个案例(说明二叉排序树可能的问题) 给你一个数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在. 左子树全部为空,从形式上看,更像一个单链表. 插入速度没有影响 查询速度明显降低(因为需要依次比较), 不能发挥BST 的优势,因为每次还需要比较左子树,其查询速度比 单链表还慢 解决方案-平衡二叉树(AVL) ...

qq_37377611的博客 328
上一篇: CF1559D2 Mocha and Diana (Hard Version) 题解
下一篇: 目录
sharp_legendgod
博客等级 码龄7年 8粉丝 114原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值