算法 | 虚树学习笔记

虚树-树上动态规划的利器 虚树 问题引入 在一类树上动态规划问题中,题目给出的询问往往包含树上的很多各节点,并保证总的点数规模小于某个值. 如果我们直接在整颗树上进行dpdpdp的话,时间复杂度与询问的次数有关,这显然是不可接受的,如果我们可以找到一种动态规划的方法,使其时间复杂度与询问中点的实际规模相关就好了. 于是虚树应运而生. 虚树概念 虚树即是一颗虚拟构建的一棵树,这个树只包含关键点以及关键lc... 阅读详情
虚树学习笔记?

blog

  • 虚树是一棵虚拟构建的树…废话 这棵树只包含关键点和关键的点,而其他不影响虚树结构的点和边都相当于进行了路径压缩…而且整棵虚树的大小不会超过关键点的2倍

    • 举个例子?
    • 比方说…4 5 6 7 表示关键点(现在你要让这些关键点也形成一棵树…要求点最少但不能破坏原来树的结构)
    • 构建完的虚树长这个样(其实这也是构建虚树时候的最坏情况…所有原来树上的点都加入了虚树之中)
    • 什么时候才会出现这种最坏的情况???当所有叶子节点都是关键点的时候…,但是很显然的是叶子结点不会超过 n 2 \dfrac{n}{2} 2n​个
  • 如何构建虚树?

    • 预处理出dfs序…将关键点按照dfs序进行排序

    • 我们使用一个栈,从栈顶到栈底的元素形成虚树的一条树链.

    • Code

      • 	sort(af + 1, af + 1 + num, cmp);
        	if(con[1] != 1) st[++top] = 1;
        	for(int i = 1; i <= num; ++i) {
        		int pos = af[i], fa = 0;
        		for(; top;) {
        			fa = GetLCA(st[top], pos);
        			if(top > 1 && dep[fa] < dep[st[top - 1]]) {
        				add(st[top - 1], st[top]), top--;
        			} else if(dep[fa] < dep[st[top]]) {
        				add(fa, st[top]), top--;
        				break;
        			} else {
        				break;
        			}
        		}
        		if(st[top] != fa) 
        			st[++top] = fa;
        		st[++top] = pos;
        	}
        	for(; top > 1; --top)
        		add(st[top - 1], st[top]);
        
  • 正确性✅?

    • 对于任意指定两点 a , b a,b a,b 的 l c a lca lca ,都存在 d f s dfs dfs 序连续的两点 u , v u,v u,v( d f n [ u ] ≤ d f n [ v ] dfn[u]\leq dfn[v] dfn[u]≤dfn[v]) 分别属于 l c a lca lca包含 a , b a,b a,b 的两棵子树,此时这 v v v 加入时按照上面的操作必定会把 l c a lca lca加入栈,所以应当加入的点都加入了。对于非 l c a lca lca 点,按照上面操作是不会出现这个点的。
HDU6035 Colorful tree
  • 题意:

    • 给你一棵 n ( 1 ≤ n ≤ 200000 ) n(1\leq n\leq 200000) n(1≤n≤200000)个节点的树…每一个节点有一个颜色.一条路径的权值定义为出现颜色集合的大小…问所有路径的权值和是多少…
  • 题解:

    当我们在考虑这个问题怎么求的时候…我们很容易地考虑到要计算每个颜色的贡献

    我们会发现这样正着做会很难…遇难则反

    • 问题转换为求有多少条路径没有出现过颜色 c c c

    事实上我们并不需要构建出每一种颜色的虚树… 只需一遍dfs就可以考虑啦!

    但是应用到了虚树的思想…

    首先一个颜色没有 c o l col col的联通块里任意两个点的路径上都不会出现 c o l col col这个颜色

    我们记录一个 s u m [ x ] sum[x] sum[x]表示遍历到当前这个点 颜色为 x x x的最高子树总大小。

    假设当前点为 n o w now now,那么接下去就要遍历它的儿子…

    • 我们记下遍历每个儿子之前的 s u m [ c o l [ n o w ] ] sum[col[now]] sum[col[now]]值为 l a s t last last
    • 那么遍历完当前儿子之后 a d d = s u m [ c o l [ n o w ] ] − l a s t add=sum[col[now]] - last add=sum[col[now]]−last就是这个儿子顶部颜色为 c o l [ n o w ] col[now] col[now]的个数
    • 那么 s z [ s o n ] − a d d sz[son]-add sz[son]−add就是颜色不为 c o l [ n o w ] col[now] col[now]的联通块大小
  • Code

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 2e5 + 10;
    struct data {
    	int nt, to;
    } a[N << 1];
    ll ans;
    int sz[N], vis[N], head[N], col[N], sum[N], cnt = 0;
    
    void add(int x, int y) {
    	a[++cnt].to = y;
    	a[cnt].nt = head[x];
    	head[x] = cnt;
    }
    
    ll js(ll x) {
    	return x * (x - 1) / 2;
    }
    
    void dfs(int u, int fa) {
    	sz[u] = 1;
    	int son = 0;
    	for(int i = head[u]; i; i = a[i].nt) {
    		int to = a[i].to;
    		if(to == fa) {
    			continue;
    		}
    		int last = sum[col[u]];
    		dfs(to, u);
    		sz[u] += sz[to];
    		int now = sum[col[u]] - last;
    		ans -= js(sz[to] - now);
    		son += sz[to] - now;
    	}
    	sum[col[u]] += son + 1;
    }
    
    int main() {
    	int n, cas = 0;
    	while(scanf("%d", &n) == 1) {
    		cnt = ans = 0;
    		int tot = 0;
    		for(int i = 1; i <= n; ++i) {
    			scanf("%d", &col[i]);
    			if(!vis[col[i]]) {
    				tot++, vis[col[i]] = 1;
    			}
    		}
    		for(int i = 1, x, y; i < n; ++i) {
    			scanf("%d%d", &x, &y);
    			add(x, y), add(y, x);
    		}
    		ans = 1ll * tot * js(n);
    		dfs(1, 0);
    		for(int i = 1; i <= n; ++i) {
    			head[i] = 0;
    			if(vis[col[i]]) {
    				// printf("%d %d\n", col[i], sum[col[i]]);
    				ans -= js(n - sum[col[i]]);
    				vis[col[i]] = 0;
    				sum[col[i]] = 0;
    			}
    		}
    		++cas;
    		printf("Case #%d: %lld\n", cas, ans);
    	}
    	return 0;
    }
    
HNOI2014 | 世界树
  • 题意

    • 给你一棵 n ( 1 ≤ n ≤ 100000 ) n(1\leq n\leq100000) n(1≤n≤100000)个节点的树 每次给你 n u m ( ∑ n u m ≤ 100000 ) num(\sum num \leq 100000) num(∑num≤100000)个控制点

      • 一个点的控制点是离它最近的且标号最小的点

      问你每个控制点控制了多少个点

  • 题解

    首先肯定是对这个 n u m num num个点构建虚树

    先预处理出虚数上的点的控制点 在去更新原树上的控制点

    (蓝色点为虚树上的点)有这么两种情况

    • 这两个点的控制点是一样(假设为 c o n [ x ] con[x] con[x]) 那么这两个点之间的所有点的控制点显然都是 c o n [ x ] con[x] con[x]

    • 这两个点的控制点是不一样的假设为 c o n [ x ] , c o n [ y ] con[x],con[y] con[x],con[y]

      首先倍增出 m i d mid mid点 再根据 c o n [ x ] , c o n [ y ] con[x],con[y] con[x],con[y]的大小判断距离相同时的情况

  • Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3e5 + 10, LOG = 20;
    struct data {
    	int nt, to;
    } a[N << 1];
    int con[N], f[N], be[N], af[N], st[N], rem[N], c[N];
    int head[N], g[N][LOG + 1], dep[N], sz[N], dfn[N];
    int n, cnt = 0, res = 0, now = 0, top = 0;
    
    void add(int x, int y) {
    	a[++cnt].to = y;
    	a[cnt].nt = head[x];
    	head[x] = cnt;
    }
    
    void predfs(int x, int fa) {
    	dfn[x] = ++res;
    	dep[x] = dep[fa] + 1;
    	sz[x] = 1, g[x][0] = fa;
    	for(int i = head[x]; i; i = a[i].nt) {
    		int to = a[i].to;
    		if(to == fa) {
    			continue;
    		}
    		predfs(to, x);
    		sz[x] += sz[to];
    	}
    }
    
    void prepare() {
    	for(int j = 1; j <= LOG; ++j)
    		for(int i = 1; i <= n; ++i)
    			g[i][j] = g[g[i][j - 1]][j - 1];
    }
    
    int GetLCA(int A, int B) {
    	if(dep[A] > dep[B]) 
    		swap(A, B);
    	for(int i = LOG; i >= 0; --i)
    		if(dep[g[B][i]] >= dep[A])
    			B = g[B][i];
    	if(A == B)
    		return A;
    	for(int i = LOG; i >= 0; --i)
    		if(g[A][i] != g[B][i])
    			A = g[A][i], B = g[B][i];
    	return g[A][0];
    }
    
    int dis(int x, int y) {
    	return dep[x] + dep[y] - 2 * dep[GetLCA(x, y)];
    }
    
    void dfs(int x) {
    	c[++now] = x, rem[x] = sz[x];
    	for(int i = head[x]; i; i = a[i].nt) {
    		int to = a[i].to;
    		dfs(to);
    		if(!con[to]) continue;
    		int d1 = dis(x, con[to]), d2 = dis(x, con[x]);
    		if((d1 == d2 && (con[to] < con[x])) || d1 < d2 || !con[x])
    			con[x] = con[to];
    	}
    }
    
    void Dfs(int x) {
    	if(!con[x]) return ;
    	for(int i = head[x]; i; i = a[i].nt) {
    		int to = a[i].to;
    		int d1 = dis(to, con[to]), d2 = dis(to, con[x]);
    		if((d1 == d2 && (con[x] < con[to])) || d1 > d2 || !con[to])
    			con[to] = con[x];
    		Dfs(to);
    	}
    }
    
    void work(int x, int y) {
    	int ny = y, mid = y;
    	for(int i = LOG; i >= 0; --i)
    		if(dep[g[ny][i]] > dep[x])
    			ny = g[ny][i];
    	rem[x] -= sz[ny];
    	if(con[x] == con[y]) {
    		f[con[x]] += sz[ny] - sz[y];
    		return ;
    	}
    	for(int i = LOG; i >= 0; --i) {
    		int nxt = g[mid][i];
    		if(dep[nxt] <= dep[x]) continue;
    		int d1 = dis(con[x], nxt), d2 = dis(con[y], nxt);
    		if(d1 > d2 || (d1 == d2 && con[y] < con[x])) mid = nxt;
    	}
    	f[con[x]] += sz[ny] - sz[mid];
    	f[con[y]] += sz[mid] - sz[y];
    }
    
    bool cmp(int x, int y) {
    	return dfn[x] < dfn[y];
    }
    
    void go() {
    	now = cnt = top = 0;
    	int num;
    	scanf("%d", &num);
    	for(int i = 1; i <= num; ++i) {
    		scanf("%d", &be[i]);
    		con[be[i]] = be[i], af[i] = be[i];
    	}
    	sort(af + 1, af + 1 + num, cmp);
    	if(con[1] != 1) st[++top] = 1;
    	for(int i = 1; i <= num; ++i) {
    		int pos = af[i], fa = 0;
    		for(; top;) {
    			fa = GetLCA(st[top], pos);
    			if(top > 1 && dep[fa] < dep[st[top - 1]]) {
    				add(st[top - 1], st[top]), top--;
    			} else if(dep[fa] < dep[st[top]]) {
    				add(fa, st[top]), top--;
    				break;
    			} else {
    				break;
    			}
    		}
    		if(st[top] != fa) 
    			st[++top] = fa;
    		st[++top] = pos;
    	}
    	for(; top > 1; --top)
    		add(st[top - 1], st[top]);
    	dfs(1), Dfs(1);
    	for(int i = 1; i <= now; ++i)
    		for(int j = head[c[i]]; j; j = a[j].nt)
    			work(c[i], a[j].to);
    	for(int i = 1; i <= now; ++i)
    		f[con[c[i]]] += rem[c[i]];
    	for(int i = 1; i <= num; ++i) 
    		printf("%d ", f[be[i]]);
    	puts("");
    	for(int i = 1; i <= now; ++i)
    		head[c[i]] = con[c[i]] = f[c[i]] = rem[c[i]] = 0;
    }
    
    int main() {
    	scanf("%d", &n);
    	for(int i = 1, x, y; i < n; ++i) {
    		scanf("%d%d", &x, &y);
    		add(x, y), add(y, x);
    	}
    	predfs(1, 0), prepare();
    	memset(head, 0, sizeof head);
    	int m;
    	scanf("%d", &m);
    	for(int o = 1; o <= m; ++o) {
    		go();
    	}
    	return 0;
    }
    
AI工程化之生成式UI & A2UI(二) 本文介绍了生成式UI框架A2UI的架构设计与核心实现。项目采用AI协作开发模式,通过ATDD(AI驱动的测试驱动开发)确保代码质量。前端SDK基于zustand实现框架无关的状态管理,包含协议解析器、存储管理、渲染器等核心模块。重点展示了基础store构建、A2UI协议解析器的实现过程,包括mock数据准备、测试用例生成和可视化调试。项目采用monorepo管理,利用vite实现高效开发构建。整个系统设计遵循模块化原则,通过清晰的接口定义实现各组件解耦,为后续功能扩展打下基础。 阅读详情

相关推荐

SDN:使用Postman控制ODL查看和下发流表

所谓,其实可被视作是SDN对网络设备的数据转发功能的一种抽象。在传统网络设备中,交换机和路由器的数据转发需要依赖设备中保存的二层MAC地址转发表或者三层的IP地址路由表,SDN交换机中使用的流表也是如此,不过在它的表项中整合了网络中各个层次的网络配置信息,从而在进行数据转发时可以使用更丰富的规则。其流表中的每个表项结果如下图所示:OpenFlow1.3流表的每个表项由6部分组成:1、匹配域:匹配域即OpenFlow1.0流表中的包头域,用于对交换机接收到的数据包的包头内容进行匹配。Ehter Des。

lyhaoyuhangyuan的博客 2535

数据结构专题——虚树

虚树(virtual tree)的概念 虚树 是将一个树的点集的某一个子集,以及该子集中点的 LCALCALCA 的集合,一起所重构出来的一棵树 虚树的用途 在树型dp中,有时候没必要对整颗树进行dp,只用对某个子集构成的虚树进行dp,大大降低了时空复杂度 例题:P2495 [SDOI2011] 消耗战 [SDOI2011] 消耗战 题目描述 在一场战争中,战场由 nnn 个岛屿和 n−1n-1n−1 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 111 的岛屿,

m0_52766855的博客 3074

Windows非分页缓冲池内存泄漏实战:PoolMon与RAMMap高效排查指南

本文详细介绍了Windows系统中非分页缓冲池内存泄漏的实战排查方法。当系统出现卡顿且内存占用异常增长时,通过RAMMap工具快速定位非分页缓冲池异常,并利用PoolMon监控内核内存分配标签,精准锁定泄漏源。文章提供了从确认症状、安装工具到使用findstr命令溯源驱动文件的完整五步排查流程,并总结了常见泄漏标签与解决方案,帮助用户高效解决深层系统内存问题。

weixin_28455801的博客 1008

浅谈虚树(虚仙人掌)

浅谈虚树

Demilly123的博客 1083

GNSS/INS松组合导航实战:如何用卡尔曼滤波提升定位精度(附MATLAB代码)

本文深入探讨了GNSS/INS松组合导航的工程实践,详细阐述了如何利用卡尔曼滤波算法融合卫星与惯性数据以提升定位精度。内容涵盖从仿真环境搭建、误差状态卡尔曼滤波器(ESKF)设计,到状态与观测方程实现、噪声参数调试及常见问题排查的全过程,并提供了可直接运行的MATLAB代码,为开发高精度、鲁棒的组合导航系统提供实战指南。

weixin_29057163的博客 161

UVM环境复位--stop_sequences()

在UVM验证环境中, stop_sequences是一个用于强制终止所有正在运行的 Sequence 的方法,通常用于动态控制激励生成流程。1.通过uvm_config_db传递事件和严格的同步机制,此方案符适用于复杂复位场景和动态测试控制。组件耦合:Driver 和 Sequence 不再直接依赖env,通过标准接口通信。竞争条件:确保 Driver 完成清理后再终止 Sequence。代码健壮性:使用非阻塞操作和事件监听,避免死锁。

qq_42779035的博客 3013

虚树(板子整理+知识总结)

思路来源 https://www.cnblogs.com/stoorz/p/12388534.html板子 https://www.cnblogs.com/zwfymqz/p/9175152.html构建过程、复杂度证明 知识点整理 以下部分来自https://www.cnblogs.com/zwfymqz/p/9175152.html 维护一个栈,建虚树的时候分三种情况,一边dfs一边建即可 一般考察虚树dp,复杂度是O(2*sumk),因为加入一个点最多多一个lca 板子整理 把..

小衣同学的博客 1212

set_output_delay的本质

set_output_delay的本质

qq_33300585的博客 3387

虚树详解

虚树大意:通过建一棵只包含询问点和不超过询问点数减一个lca的树来减少点的个数,降低时间复杂度 这东西不难,常用于辅助树形dp,难点在于dp… 使用该算法的标志为不确定组的询问次数与给出的询问点数和 例如: 每次询问w个数,∑i=1qwi=300000\sum_{i=1}^qw_i=300000\quad∑i=1q​wi​=300000 算法: 构建过程十分简单,放心食用 举个例子:P2495 ...

tylon2006的博客 908

【OpenClaw从入门到精通】第37篇:教育“龙虾”进化论——从答疑助教到全流程智能教学系统(2026实测版)

2026年,教育AI已从被动答疑的L1级进化至主动教学的L4级,清华开源的OpenMAIC平台更是打破传统慕课局限,实现互动式AI课堂。本文基于天津工业大学、西北农林科技大学等高校的真实应用案例,结合腾讯云、天翼云的实操指南,详解OpenClaw在教育场景的四层进化路径。核心内容包括:L1-L4级教育自动化架构解析、清华OpenMAIC L4级AI课堂深度拆解、从零搭建智能答疑(QQ群机器人)+作业批改+学情分析全流程系统,以及高校网络安全合规部署方案。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 774

手把手教你学Simulink——基于电机驱动系统的场景实例:永磁同步电机(PMSM)在电动汽车中的矢量控制仿真

随着全球对环境保护的关注增加,电动汽车(Electric Vehicle, EV)因其环保特性而受到广泛关注。永磁同步电机(Permanent Magnet Synchronous Motor, PMSM)由于其高效率、高功率密度和良好的动态响应性能,在电动汽车驱动系统中得到了广泛应用。矢量控制(Field-Oriented Control, FOC)是实现PMSM高性能控制的关键技术之一,它能够实现对电机转矩和磁场的独立控制,从而达到类似直流电机的控制效果。本文将详细介绍如何使用来构建一个。

MHD0815的博客 1万+

虚树详细讲解

新学虚树,写篇文章仔细地回顾一下吧。。。这玩意花了挺长时间的。 什么是虚树 虚树常常被使用在树形 dpdpdp 中,就比如这题。当一次询问仅仅涉及到整颗树中少量结点时,为每次询问都对整棵树进行 dpdpdp 在时间上是不可接受的。此时,我们建立一颗仅仅包含部分关键结点的虚树,将非关键点构成的链简化成边或是剪去,在虚树上进行 dpdpdp 。 虚树包含所有的询问点及它们之间的 lcalcalca 。显然虚树的叶子节点必然是询问点,因此对于某次含有 kkk 个点的询问,虚树最多有 kk...

weixin_45630722的博客 3059

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

虚树学习笔记

虚树学习笔记

Dyc780511的博客 1123

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

算法学习笔记汇总

讲道理我真的没有写过什么学习笔记… 虚树

Averyta的博客 220

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

NOI数据结构:虚树

NOI数据结构:虚树

青少年趣味编程 1174

【学习笔记】虚树

虚树学习笔记 前言:前两天北航校赛有一题考了这个,看到题解觉得挺神奇的,之后又在南昌网络赛的题解里看到这个词,赶紧先来把板子学了 update1: 把南昌网络赛的F题补上了,写的时候尝试一下了把虚树写进struct里 先了解几个基本的问题 Q:虚树是做什么的? A:虚树就是把一棵树上的对问题有影响的点扒出来,建一棵新的树 Q:为什么会需要这个东西? A:如果题目有多组询问,每次询问的点不...

weixin_30483013的博客 206

图论专题-学习笔记:虚树

图论专题-学习笔记:虚树1. 前言2. 详解2.1 虚树定义2.2 虚树构造2.3 例题3. 总结4. 参考资料 1. 前言 虚树,主要是用于一类树上问题,这类问题通常是需要取一些关键点,然后要在这些关键点和其 LCA 上做一些奇怪的玩意。 关键前置知识:LCA。 2. 详解 2.1 虚树定义 首先我们需要知道虚树是什么: 现在给出一棵 nnn 个点的树,从中选取出 kkk 个关键点,这些关键点以及其两两的 LCA 构成了对于这些关键点而言的虚树,特别注意如果取出来的树不连通的话我们还需要一个根节点来连通。

Plozia 的小窝 651

集训 Day 3 总结 虚树 + dfs tree + 基环树

虚树,顾名思义是 只关注原树上的某些,在保留原树祖孙关系的前提下建出的一棵边数、点数大大减少的树适用于优化某些在整棵树上进行dpdfs等操作通常是题目中出现多次询问,每次给出树上的一些关键点,同时保证∑关键点数≤n,很大可能就是建出虚树来处理概括来说,虚树只进行两步操作和。

qq_56326461的博客 1422

知识点 - 虚树

知识点 - 虚树 解决问题类型: 利用虚树,可以对于指定多组点集 SSS 的询问进行每组 O(∣S∣log2n+f(∣S∣))O(|S|log_2n+f(|S|))O(∣S∣log2​n+f(∣S∣)) 的回答,其中 f(x)f(x)f(x)指的是对于树上有 xxx 个点的情况下单组询问这个问题的时间复杂度。可以看到,这个复杂度基本上(除了那个 log2nlog_2nlog2​n以外)与 nnn ...

qq_41848675的博客 548

虚树

虚树,选择k个点,构成一个树,这个树只包含所选点和他们两两之间的lca, 特点为这个虚树上的点不超过2*k个,若有多组k,则复杂度为2 * ∑ k。 模板: int tp,st[MAX_N]; vector<int>sv[MAX_N];//存放虚树,用完后clear,复杂度为2*k int dep[MAX_N];//为树的深度 void build(int s,int count){...

EDGiboy的博客 359

虚树学习小记

## 虚树是什么 虚树指在原树上选择需要的点和它们的$LCA$组成的一棵树。这样可以使在树DP时顶点数更少,从而减少时间复杂度。一般用于有多组数据且能保证所有数据访问的点的和不超过规定范围。

tanjunming2020的博客 1557

虚树模板题

虚树是这样一种思想,很多时候一棵树里只有一些点是我们会用到的,如果我们只对这些点进行操作,复杂度可以接受,但是还有很多对答案完全没影响的点,如果把他们也加进来复杂度就太高了,所以一个很自然的想法是,如果把对答案有影响的点称为关键点,我们能不能建一颗只含关键点的树,然后在这个树上计算答案?这里还有个麻烦的地方是,虚树上两点间的边,可能是原始数上很多条边,我们断开虚树上的边,实际上是在原始树上多条边中选一条断开,那显然应该选边权最小的那个,那么我们建树的时候,每次把。为根的子树内所有集合中的点,都到不了。

Maxwell_Newton的博客 839

[学习笔记]虚树

前言&&思想 一些给定树上一些点集,要处理和该点集有关的询问(例如和点集关系,点集选择限制)的题目, 很多子树没有变化,暴力没有意义。 提取出有关的点和路径,构成虚树 虚树上DP等等,难点往往在于找到非虚树部分的答案。 建立 1.暴力sort再sort LCA一般都要用,所有点按照dfn序sort,相邻两点的LCA就是所有涉及到的LCA 注意,LCA可能算重!...

weixin_33859231的博客 281
上一篇: Codeforces293 | Round#174 Div1| 题解报告
下一篇: 算法学习笔记汇总
Averyta
博客等级 码龄7年 1粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值