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

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

思路来源

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

板子整理

把0号点当做一个默认出现的虚点,这样统一了很多情况

key[i]=1的点是虚树标记的点,par关系是新建的虚树

#include<bits/stdc++.h>
using namespace std;
const int N=200010,LG=20;
int n,m;
vector<int>e[N]
int stk[N],top;//虚树栈 
int dep[N],f[N][LG+1];//lca
int par[N];//虚树 
bool key[N];//关键点 
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=LG;i>=0;i--){
		if(dep[f[x][i]]>=dep[y]){
			x=f[x][i];
		}
	}
	if(x==y)return x;
	for(int i=LG;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			x=f[x][i],y=f[y][i];
		}	
	}
	return f[x][0];
}
void dfs(int u,int fa){
	dep[u]=dep[fa]+1;
	f[u][0]=fa;
	for(int i=1;i<=LG;i++){
		f[u][i]=f[f[u][i-1]][i-1];
	}
	if(key[u]){
		int p=lca(u,stk[top]);
		if(p!=stk[top]){
			while(dep[stk[top-1]]>dep[p]){
				par[stk[top]]=stk[top-1];
				top--;
			}
			par[stk[top]]=p;
			top--;
			if(stk[top]!=p){
				stk[++top]=p;
			}
		}
		stk[++top]=u;
	}
	for(int v:e[u]){
		if(v==fa)continue;
		dfs(v,u);
	}
}
void build(){//以0为虚根 
	top=1;
	dfs(1,0);
	for(int i=top;i>=1;i--){
		par[stk[i]]=stk[i-1];	
	} 
} 
int main(){
	return 0;
}

支持多组询问的虚树(2024.2.11补充)

先dfs一遍,得到dfs序,

对于单组询问的询问点,先按dfn增序排序,

然后套用建一次虚树的方式,此时虚根仍然是0

以abc340g为例,也可参考洛谷p2495【消耗战】

KAJIMA CORPORATION CONTEST 2024(AtCoder Beginner Contest 340) G. Leaf Color(虚树+dp)-优快云博客

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<queue>
using namespace std;
typedef array<int,2> a2;
typedef array<int,3> a3;
const int N=2e5+10,LG=20,mod=998244353;
int n,u,v,ans,a[N];
vector<int>col[N],e[N],g[N];
int dep[N],f[N][LG+1],dfn[N],c;
bool key[N];//关键点 
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=LG;i>=0;i--){
		if(dep[f[x][i]]>=dep[y]){
			x=f[x][i];
		}
	}
	if(x==y)return x;
	for(int i=LG;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			x=f[x][i],y=f[y][i];
		}	
	}
    //printf("x:%d y:%d lca:%d\n",x,y,f[x][0]);
	return f[x][0];
}
void dfs(int u,int fa){
	dep[u]=dep[fa]+1;
    dfn[u]=++c;
    //printf("u:%d dfn:%d\n",u,dfn[u]);
	f[u][0]=fa;
	for(int i=1;i<=LG;i++){
		f[u][i]=f[f[u][i-1]][i-1];
	}
	for(auto &v:e[u]){
		if(v==fa)continue;
		dfs(v,u);
	}
}
void add(int x,int y){
    //if(x==y)return;
    //printf("x:%d y:%d\n",x,y);
    g[x].push_back(y);
}
a2 dfs1(int u){
    //printf("u:%d\n",u);
    a2 dp={1,1};
    a3 h={1,0,0};
    for(auto &v:g[u]){
        auto dp2=dfs1(v);
        dp[0]=1ll*dp[0]*dp2[0]%mod;
        dp[1]=1ll*dp[1]*(dp2[1]+dp2[0])%mod;
        h[2]=(1ll*h[2]*(dp2[0]+dp2[1])%mod+1ll*h[1]*dp2[1]%mod)%mod;
        h[1]=(1ll*h[1]*dp2[0]%mod+1ll*h[0]*dp2[1]%mod)%mod;
        h[0]=1ll*h[0]*dp2[0]%mod;
    }
    if(key[u]){
        ans=(ans+dp[1])%mod;
    }
    else{
        ans=(ans+h[2])%mod;
        dp[1]=(dp[1]+mod-1)%mod;//非关键点的不能当叶子
    }
    key[u]=0;
    g[u].clear();
    return dp;
}
void build(vector<int>&a){//以0为虚根 
    static int stk[N],top;//虚树栈 
    sort(a.begin(),a.end(),[&](int x,int y){
        return dfn[x]<dfn[y];
    });
    int sz=a.size();
    stk[top=1]=a[0];
    key[a[0]]=1;// 标记为关键点
    for(int i=1;i<sz;++i){
        int u=a[i];
        key[u]=1;// 标记为关键点
		int p=lca(u,stk[top]);
		if(p!=stk[top]){
			while(dep[stk[top-1]]>dep[p]){
				add(stk[top-1],stk[top]);
				top--;
			}
			add(p,stk[top]);
			top--;
			if(stk[top]!=p){
				stk[++top]=p;
			}
		}
		stk[++top]=u;
	}
	for(int i=top;i>=2;i--){
		add(stk[i-1],stk[i]);
	}
    dfs1(stk[1]); 
} 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        col[a[i]].push_back(i);
    }
    for(int i=1;i<n;++i){
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1,0);
    for(int i=1;i<=n;++i){
        if(!col[i].size())continue;
        build(col[i]);
        //puts("");
    }
    printf("%d\n",ans);
	return 0;
}

虚树 virtual-tree 我们发现,如果一棵树中真正需要处理的点很少,而总共点数很多时,可以只处理那些需要的点,而忽略其他点。 因此我们可以根据那些需要的点构建虚树,只保留关键点。 oi-wiki上对虚树的介绍 我们根据一下方式建立虚树: 现将所有需要处理的关键按照欧拉序排序。 用一个栈维护一条从根节点到上一个处理过个点的链(虚树上的链)。 考虑将一个新的点加入虚树: 求出这个点与栈顶元素的 \(Lca\... 阅读详情

相关推荐

数据结构入门9—虚树

原本以为K-D Tree比虚树难,但是后来发现虚树反而难理解一些。主要是关于找LCA的问题。 假如我们有一些点是一定要在虚树里的,那么需要保证他们任意两点的LCA也在虚树里,否则树的结构就改变了。 那么就需要用到dfs序了。 我们求得每个点的dfs序,然后把这些点按dfs序排序,那么他们所有的LCA肯定是排序后某相邻两点的LCA。这个是可以证明的,我就不证了。 然后找到LCA之后就是找每个

Serene 1903

数据结构专题——虚树

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

m0_52766855的博客 3074

FFT板子整理

FFT 今天把之前一直没有系统整理的FFT弄了一下,考虑到分治版本的效率太低,于是还是写了蝴蝶变换的板子,感觉理解起来有些困难但是还是能够接受。 要记得inv=1inv=1inv=1是DFT,inv=−1inv = -1inv=−1是IDFT,之前比赛就这边有问题,要记住。 还有在计算答案的时候,需要对于结果除以整个的长度进行修正!! 我终于把之前没有看懂的复数根看懂了QAQ 找了一道十分裸的板子...

eternal‘s blog 603

浅谈虚树(虚仙人掌)

浅谈虚树

Demilly123的博客 1083

pikachu靶场: 暴力破解第四关(token防爆破)

Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个 Token 同时将此 Token 返回给客户端。此外,Token 是有时效的,一段时间之后或下一次请求时用户需要重新验证。

X_shiguang的博客 1720

智能座舱通信技术解析:从CAN总线到车载以太网与V2X

在汽车电子与智能网联快速融合的背景下,座舱智能化已不再是简单的屏幕堆砌,而是依赖底层通信技术构建的复杂系统。CAN总线因高可靠性与确定性传输,持续承担车身控制与安全信号的传递;车载以太网则凭借高带宽优势,成为多屏高清视频与OTA升级的核心通道;V2X车路协同技术进一步将座舱与外界的实时信息互联。理解这些技术的分工协作,是掌握智能座舱架构、开展座舱测试与故障排查的关键。本文从实际测试经验出发,梳理不同总线在座舱内部及外部的应用逻辑,结合低成本的实验台架搭建指南,展示从信号采集、网关转发到多媒体流传输的完整链路

weixin_29284657的博客 341

笛卡尔树(知识总结+板子整理)

思路来源 https://blog.youkuaiyun.com/qq_36056315/article/details/79845193(清晰易懂) https://www.cnblogs.com/reverymoon/p/9525764.html(板子+例题) 知识总结 笛卡尔树是形如上图的一棵树,满足 ①堆的性质,如本图,小根堆,两子的值大于等于父亲的值 ②二叉搜索树性质,即左子树的点k...

小衣同学的博客 1万+

从报错到成功:手把手教你避坑clusterProfiler安装全流程

本文详细解析了clusterProfiler安装过程中的常见报错及解决方案,从CRAN安装误区到Bioconductor拼写错误,再到依赖包安装失败等问题,提供了五步正确安装法。特别适合生物信息分析新手快速掌握R包安装技巧,避免踩坑。

weixin_30859423的博客 379

【学习笔记】虚树

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

weixin_30483013的博客 206

感应电机无速度传感器FOC控制原理与Simulink仿真实践

无速度传感器FOC控制是电机驱动领域的重要技术,通过算法重构实现仅依赖电气参数的闭环控制。其核心原理基于电机数学模型,利用Clark/Park变换和滑模观测器估算转子位置和转速。这种技术在工业伺服系统中具有显著价值,能有效降低系统成本并提高可靠性。典型应用场景包括纺织机械、风机驱动等需要精确转速控制的设备。本文以感应电机为例,详细解析了无感FOC的Simulink实现方法,特别关注滑模观测器设计和双闭环控制策略,为工程师提供可直接复用的参数调优经验。

weixin_29189987的博客 259

【C/C++ 性能优化】提高C++程序的缓存命中率以优化性能

在探讨计算机性能优化的旅程中,我们常常被引导去关注算法的复杂度、代码的优化,或是更高效的数据结构。然而,有一个经常被忽视的角色在幕后默默地影响着程序的运行效率——那就是缓存(Cache)。正如哲学家亨利·戴维·梭罗在《瓦尔登湖》中所说:“细节是造成美丽的源泉”,在软件开发的世界里,对缓存的理解和优化,就是那些决定程序性能优雅与否的细节。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 3732

Prufer序列(知识总结+板子整理)

思路来源 https://www.cnblogs.com/zwfymqz/p/8869956.html https://www.luogu.com.cn/blog/xht37/solution-p6086 https://www.luogu.com.cn/blog/hekaiyu/prufer-xu-lie 知识总结 常用于生成树计数,毕竟都搞出序列了。 一个长度为n-2的Prufer序列,唯一对应一棵n个点固定形态的无根树。 T->P(Tree->Prufer) 找到编.

小衣同学的博客 3982

2024.12.29 【RNA-seq】Rawdata数据缺失问题与解决方案

Fastq格式是一种用于存储高通量测序数据的文件格式,包含序列和相应的质量信息。第一行以开头,后接序列标识符;第二行是测序的DNA序列;第三行以开头,可能会跟随序列标识符;第四行是对应的质量值,以ASCII字符表示。Rawdata的数据完整性通常情况下是没有问题的,但我们仍然需要对下机数据进行验证,确保后续分析的正常进行,好的分析习惯可以提高整体的分析效率,避免很多不必要的麻烦。

1109

后缀自动机(知识整理+板子总结)

后缀自动机(知识整理+板子总结)

小衣同学的博客 5366

22、用户界面流程(UI Flow)全解析

本文全面解析了用户界面流程(UI Flow)的概念、创建步骤及其在系统设计中的应用。通过示例和操作步骤,详细介绍了如何确定屏幕范围、识别屏幕、创建过渡和标记触发器,并阐述了UI Flow在导航识别、验证、可用性优化、测试用例开发和需求推导中的重要作用。文章还结合问答系统案例,展示了UI Flow的实际应用价值,帮助读者深入理解并有效运用这一工具提升系统用户体验。

rice5的博客 153

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

(转载)回文树/回文自动机(知识整理+板子总结)

心得 回文树,又名回文自动机,是一个东西 去年网络赛之后一直想学这个东西,一直碍于太难没学…… 今天有个SA+PAM(后缀数组+回文自动机)的题,快100个队过,我就来补了…… 一看我收藏的那篇讲解回文树的博客2W访问,看来你国网友都会了 原理感觉和AC自动机很类似,真的很巧妙啊, 由于now是从cur补字母c构成的回文串, 所以fail[now]要从fail[cur]失配时的最长后...

小衣同学的博客 532

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

线段树优化建图(知识总结+板子整理)

思路来源 https://www.cnblogs.com/Miracevin/p/9863080.html 知识点整理 原博主的图片,出树和入树 和 本代码里的tin和tout正好相反…… 两棵树,一棵tin树,一棵tout树, 让tin[k]中的父亲向儿子连边,代表u向区间连边, 让tout[k]中的儿子向父亲连边,代表区间向点u连边, 让入树和出树的叶子结点指向相同的真实节点...

小衣同学的博客 1077

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Linux 之 arm linux 板子与 ubuntu 使用 nfs 进行 mount 挂载进行文件传输的简单整理

Linux/Ubuntu开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。本节介绍,arm linux 与 ubuntu 使用 nfs 进行 mount 挂载进行文件传输的简单整理。如果有不足之处,欢迎指出,或者你有更好的方法,欢迎留言。NFS是基于UDP/IP协议的应用,其实现主要是采用远程过程调用RPC机制,RPC提供了一组与机器、操作系统以及低层传送协议无关的存取远程文件的操作。RPC采用了XDR的支持。

仙魁XAN 3119

并查集板子整理

基本原理:每个集合用一棵树来表示,树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。注:在维护并查集的过程中,也可以同时维护其他信息(比如,集合中元素的数量),视具体情况分析。求x的集合编号:while(p[x]!=x) x=p[x];2.询问两个元素是否在一个集合当中。优化:路径压缩(直接指向祖宗节点)判断树根:if(p[x]==x)如何合并两个集合:p[x]=y;

Haoing947的博客 304

Counting Cycles Aizu - 1388 虚树 模板题

点我看题 题意 给出一个图 ,问其中有多少个简单环。 边数最多比点数多15 解题思路 边数最多比点数多15。 这是一个很经典的条件。 1.想到状压枚举,2.想到建出生成树,然后暴力加边。 思考枚举边的时候如何判断是否有环。 这是一个图论小技巧,将选出来的边的端点 往上异或边异或到根节点, 异或完成后,所有值等于1的边就是应该要选的边。 然后暴力判断这些边是否能构成一个简单环即可。 但这样 复杂度会...

lifelike 386

面向考研的数据结构板子

考研复习对着书看了一遍数据结构之后总觉得缺了点什么,正好以前打比赛的板子也找不到了,就在这写一点数据结构的基础板子找找手感,举的例子也都是一些简单题,希望能对复习有所帮助。我在写板子的时候尽量附上了可供测试的数据,并尽量找到oj的链接以便您能调试评测,如果妹有附上说明我真的妹有找到请理解(或者说我是真的懒)。请注意,作者的水平有限,很有可能会出现他意想不到的bug,或者他只过了弱测,并没有进行更强数据的校验,如果您发现出现了错误或者bug,请及时通知我,给您带来的不便敬请谅解。另:本人整理的顺序是按照自己的

zhousiyuan0515的博客 1582

Splay伸展树(平衡树)(知识整理+板子总结)

心得 自己去年八月初学的时候,迷迷糊糊不怎么懂, 上学期学了数据结构AVL平衡树,现在再看才算完全明白 Splay平衡树, 理解了之后当板子用就可以了, 虽然还是要写一篇博客,万一哪天忘了之后想再学呢~ 思路来源 https://www.cnblogs.com/cjyyb/p/7499020.html(知识点整理 yyb的博客) https://blog.youkuaiyun.com/zhouz...

小衣同学的博客 543

一些关于ACM板子笔记

我是菜鸟ACMer(qwq),之前整理一些板子笔记,适合刚起步的小白,容易看懂,不过没有很完整,因为没写完就退役了,可以看看目录有哪些知识点噢。

lwltql的博客 2118

树相关板子整理

二叉搜索树 const ll maxn = 1e3 + 10; typedef struct Node *BinTree; ll n, s = 0, t = 0, k = 0; ll a[maxn], b[maxn], c[maxn]; struct Node { ll data; BinTree left, right; }; //建立二叉搜索树 BinTree CreatTree(BinTree BST, ll x) { if (!BST) { BS

_Kiwi_berry的博客 170

斯坦纳树(板子整理)

板子整理 如果不能保证,要加入stein树的点没有重复, 建议不要如板子里这么写,因为去重之后,不能确定点在vec里排第几位了, 当然可以魔改成不去重,但是处理时是st[it]=st[it] | endSt的写法 #include <bits/stdc++.h> using namespace std; #define pii pair <int, int> #...

小衣同学的博客 336
上一篇: The 13th Chinese Northeast Collegiate Programming Contest D. Master of Data Structure(虚树)
下一篇: 长链剖分(知识点整理+板子总结)
小衣同学
博客等级 码龄9年 1444粉丝 995原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值