虚树-树上动态规划的利器

虚树


问题引入

在一类树上动态规划问题中,题目给出的询问往往包含树上的很多各节点,并保证总的点数规模小于某个值.

如果我们直接在整颗树上进行dpdp的话,时间复杂度与询问的次数有关,这显然是不可接受的,如果我们可以找到一种动态规划的方法,使其时间复杂度与询问中点的实际规模相关就好了.

于是虚树应运而生.

虚树概念

虚树即是一颗虚拟构建的一棵树,这个树只包含关键点以及关键lcalca的点,而其他不影响虚树结构的点和边都相当于进行了路径压缩,整颗虚树的规模不会超过关键点数目的两倍.

举个栗子

原树

这里写图片描述


虚树

包含关键点 1 2 3的虚树

这里写图片描述

包含关键点 1 3 7 8 的虚树

这里写图片描述

其中6是关键lcalca节点

很显然,其他不是那么关键的点及边形成的路径我们都将他们压缩到了一条边,例如在第二个虚树中,我们相当于把161−6的路劲压缩到了边161−6中,而99号节点这种非关键点我们直接扔掉了,因为我们在dp的时候不会用到99号点.

虚树构建

预处理我们对整颗树得到dfs序列(即前序遍历),记为dfn[u].

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

当我们得到一些询问点(关键点)的时候,对这些点按照他们的dfn[u]dfn[u]值进行排序,然后从dfndfn值小的开始扫描,结合栈中保存的树链信息就可以将这颗虚树构建出来.

假设我们当前扫到的关键点为uu,栈指针为top,栈为stkstk.

1.如果栈为空,或者栈中只有一个元素,那么显然应该:
stk[++top]=u;stk[++top]=u;

2.取lca=LCA(u,stk[top])lca=LCA(u,stk[top]),如果lca=stk[top]lca=stk[top],则说明uu点应该接着stk[top]点延长当前的树链.做操作:
stk[++top]=u;stk[++top]=u;

3.如果lcastk[top]lca≠stk[top],则说明uustk[top]分属lcalca的两颗不同的子树,且包含stk[top]stk[top]的这颗子树应该已经构建完成了,我们需要做的是:
lcalca的包含stk[top]stk[top]子树的那部分退栈,并将这部分建边形成虚树.如果lcalca不在栈(树链)中,那么要把lcalca也加入栈中,保证虚树的结构不出现问题,随后将uu加入栈中,以表延长树链.

代码实现

//实现逐个将关键点插入形成一颗虚树
void insert(int u){if(top <= 1) {stk[++top] = u;return ;}int lca = LCA(u,stk[top]);if(lca == stk[top]) {stk[++top] = u;return ;}while(top > 1 && dfn[lca] <= stk[top-1]) {addedge(stk[top-1],stk[top]);--top;}if(lca != stk[top]) stk[++top] = lca;stk[++top] = u;
}

虚树例题

[SDOI2011]消耗战

题意

给出n个点的一棵带有边权的树,以及qq个询问.每次询问给出k个点,询问这使得这kk个点与1点不连通所需切断的边的边权和最小是多少.

题解

dp[n]dp[n]表示从nn开始不能到达其子树中的关键点所需切断的最小边权和.

me[u]表示切断11u的路径中的边权最小值.

vvu的直接儿子.

如果vv是关键节点,那么dp[u]+=me[v][1],否则dp[u]+=min(me[v],dp[v])[2]dp[u]+=min(me[v],dp[v])[2]
(第[2][2]个转移方程的解释:要么直接切断1v1−v的路径,要么使得从vv出发不能到达其子树的关键点.)

显然我们不能针对每个询问对整颗子树进行dp,时间复杂度过高,而我们发现那些非关键点我们没有必要在dpdp的时候考虑,所以使用虚树.

代码

const int maxn = 250007;
const int inf = 1e9;
vector<int> RG[maxn],VG[maxn];
int U[maxn],V[maxn],C[maxn];
int dfn[maxn],deep[maxn];ll me[maxn];int fa[maxn][20];
int stk[maxn],top;
int n,m,idx;
void dfs(int u){dfn[u] = ++idx;deep[u] = deep[fa[u][0]] + 1;for(int e : RG[u]){int v = U[e] ^ V[e] ^ u;if(v == fa[u][0]) continue;me[v] = C[e];if(u != 1 && me[u] < me[v]) me[v] = me[u];fa[v][0] = u;dfs(v);}
}int LCA(int u,int v){if(deep[u] < deep[v]) swap(u,v);int delta = deep[u] - deep[v];for(int i = 19;i >= 0;--i){if((delta >> i) & 1) u = fa[u][i];}for(int i = 19;i >= 0;--i){if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];}if(u == v) return u;return fa[u][0];
}bool comp(int a,int b){return dfn[a] < dfn[b];
}void insert(int u){if(top == 1) {stk[++top] = u;return;}int lca = LCA(u,stk[top]);if(lca == stk[top]) {stk[++top] = u;return ;}while(top > 1 && dfn[lca] <= dfn[stk[top-1]]){VG[stk[top-1]].push_back(stk[top]);--top;}if(lca != stk[top]) {VG[lca].push_back(stk[top]);stk[top] = lca;} stk[++top] = u;
}int idq[maxn],mark[maxn];ll DP(int u){ll cost = 0;for(int v : VG[u]){cost += min(me[v],DP(v));}VG[u].clear();if(mark[u]) return me[u];else return cost;
}int main(){init();ios::sync_with_stdio(false);cin >> n;for(int i = 1;i < n;++i){cin >> U[i] >> V[i] >> C[i];RG[U[i]].push_back(i);RG[V[i]].push_back(i);}dfs(1);for(int t = 1;t <= 19;++t) for(int i = 1;i <= n;++i){fa[i][t] = fa[fa[i][t-1]][t-1];}cin >> m;for(int i = 0;i < m;++i){int sz;cin >> sz;for(int j = 0;j < sz;++j){cin >> idq[j];mark[idq[j]] = 1;}sort(idq,idq+sz,comp);top = 0;stk[++top] = 1;for(int j = 0;j < sz;++j) insert(idq[j]);while(top > 0) {VG[stk[top-1]].push_back(stk[top]);top--;}cout << DP(1) << endl;for(int j = 0;j < sz;++j) VG[idq[j]].clear(),mark[idq[j]] = 0;VG[0].clear();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321114.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微软推出Visual Studio Kubernetes工具包预览版

微软表示&#xff0c;利用 Visual Studio Kubernetes 这个工具&#xff0c;使用者可以直接在该环境中&#xff0c;构建 Kubernetes 容器应用程序项目&#xff0c;或者让现有的 .NET 网页应用程序也兼容 Kubernetes。除了公有云基础架构环境要支持 Kubernetes&#xff0c;微软现…

基于docker 如何部署surging分布式微服务引擎

1、前言转眼间surging 开源已经有1年了&#xff0c;经过1年的打磨&#xff0c;surging已从最初在window 部署的分布式微服务框架&#xff0c;到现在的可以在docker部署利用rancher 进行服务编排的分布式微服务引擎&#xff0c;再把业务进行剥离&#xff0c; 通过配置路径就能驱…

DevOps 实践:千里之行

在上一篇 DevOps 渊源&#xff1a;角色消融 中我们分析了在作坊式团队中的责任重叠&#xff0c;也回顾了 DBA 角色的消融。那么&#xff0c;如今我们讲的 DevOps 又是什么角色的消融呢&#xff1f; 我想你已经猜到了&#xff0c;接下来要消融的角色就是运维人员了。那这次又是什…

约数个数

约数个数 题目大意&#xff1a; 求a到b之间每个数的约数的个数之和 原题&#xff1a; 题目描述 定义f(x)为x的约数个数&#xff0c;x为正整数。 f(a)f(a1)……f(b)&#xff0c;即a,b之间每个数的约数的总和。 输入 一行两个正整数a、b&#xff0c;以一个空格隔开。 输出…

asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程...

最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ &#xff01;因此学习了一下这个开源框架&#xff01;下面对Exceptionless的学习做下笔记&#xff01;Exceptionless是什么&#xff1f;能做什么呢&#xff1f;“Exceptionless”这…

使用 IIS 在 Windows 上托管 ASP.NET Core2.0

准备&#xff1a;操作系统&#xff1a;Windows Server 2008 R2 或更高版本开发环境&#xff1a;VS2017回到顶部第一步&#xff1a;新建项目ASP.NET Core Web应用程序在 Visual Studio 中&#xff0c;选择“文件”>“新建”>“项目”。在新建项目对话框的左侧窗格选择“.N…

数学推导题,NTT,快速数论变换,Wannafly-导数卷积

导数卷积 题目描述 题解 参考了一下标程的推导过程,因为这个推导对我这种数学弱渣真的有点难鸭. [1]f(x)f(x)f(x)的iii次导函数: f(i)(x)ai∗i!0!ai1∗(i1)!1!∗x1...an−1∗(n−1)!(n−1−i)!∗xn−1−if^{(i)}(x) a_{i}*\frac{i!}{0!} a_{i1}*\frac{(i1)!}{1!}*x^{1} ...…

使用 C# 代码实现拓扑排序

0.参考资料尊重他人的劳动成果&#xff0c;贴上参考的资料地址&#xff0c;本文仅作学习记录之用。https://www.codeproject.com/Articles/869059/Topological-sorting-in-Csharphttps://songlee24.github.io/2015/05/07/topological-sorting/https://www.cnblogs.com/skywang1…

ASP.NET Core 2.1带来SignalR、Razor类库

随着.NET Core 2.1的发布&#xff0c;微软推出了 ASP.NET Core 2.1。这是一个强大的版本&#xff0c;包括实时通信库SignalR&#xff0c;更新的模板使GDPR更容易遵守&#xff0c;并且针对Angular、React&#xff0c;以及React Redux更新了SPA模板。在2013年发布传统的ASP.NET时…

针对ASP.NET Core Web API的先进架构

.NET Core 最初是在2016年发布的&#xff0c;随着.NET Core 2.0的发布&#xff0c;微软拥有了下一个通用、模块化、跨平台和开源的平台主版本。.NET Core已经创建了许多API&#xff0c;在当前版本的.net框架中均可用。它最初是为下一代ASP.NET解决方案而创建的&#xff0c;但现…

ASP.NET Core 2.1 使用Docker运行

1.新建一个 ASP.NET Core 2.1 项目然后运行一下项目&#xff0c;确保我们刚刚建立的项目可以正常运行。2.编写 Dockerfile新建一个文本文件&#xff0c;命名为 DockerfileFROM microsoft/dotnet:2.1-aspnetcore-runtimeWORKDIR /appCOPY . .EXPOSE 80ENTRYPOINT ["dotnet&…

【DP】和谐的奶牛(jzoj 1750)

和谐的奶牛 题目大意&#xff1a; 有一些括号&#xff08;保证是合法的&#xff0c;合法&#xff1a;每一个左括号都有自己配对的有括号&#xff09;&#xff0c;现在要将这些括号分为两组&#xff08;其中一组可以为空&#xff09;&#xff0c;分完组后括号的顺序要和原来的…

费用流-Wannafly Day2 TwoGraph-神题

TwoGraph 题意 题解 这真是一道神题,这题有两点比较难想,其中第一点是最难想的. 我们先考虑只有一张图的情况. 性质: [1]如果给每个点匹配一条边,形成一个(点,边)(点,边)(点,边)对,其中点不能重复出现,边也不能重复出现.那么这些对形成的图的联通块要么是树,要么是环套树. 证…

ASP.NET Core Web API 与 SSL

SSL一直没有真正研究过SSL&#xff0c;不知道下面的理解是否正确。SSL是Secure Sockets Layer的缩写&#xff0c;它用来保护服务器和客户端之前的通信。它是基于信任加密的概念。在介绍SSL的原理之前&#xff0c;首先介绍一下加密&#xff08;Encryption&#xff09;的概念。刷…

【模拟】聊天服务器的外部流量

聊天服务器的外部流量 题目大意&#xff1a; 有一个通讯系统&#xff0c;可以将某人邀请进来&#xff08;name&#xff09;&#xff0c;也可以将某人T出去&#xff08;-name&#xff09;&#xff0c;也可以向群中的所有人发一条信息&#xff08;name&#xff1a;…&#xff0…

GitHub宣布GitHub Education 新计划,学校可免费用企业版

今天 GitHub 宣布面向所有学校和教育机构开放 GitHub Education&#xff0c;方便学生和老师免费使用 GitHub 企业版功能&#xff0c;以及学生开发者工具包、GitHub 教室、培训等资源。2014 年&#xff0c;GitHub 推出了学生开发者工具包&#xff0c;其中包括 Azure 等云服务、G…

【dfs】聚会

聚会 题目大意&#xff1a; 有一些树&#xff0c;求深的树的深度 原题 解题思路&#xff1a; 从一个根出发&#xff0c;dfs往下搜 代码&#xff1a; #include<cstdio> #include<iostream> #include<cstring> using namespace std; int n,t,g,w,ans,c[2…

2018 大湾区(深圳) .NET技术分享交流会 第一期

.NET Core 2.1 已于2018年5月30日正式发布&#xff0c;邀请粤港澳大湾区.NET技术专家和从业人员&#xff0c;一起分享与交流.NET技术的发展方向&#xff0c;提高粤港澳大湾区.NET技术交流氛围&#xff0c;挖掘.NET高级人才&#xff0c;为改善.NET生态系统贡献力量&#xff0c;使…

卡车

卡车 题目大意&#xff1a; 有一个卡车向里面放东西&#xff08;重量要么是一要么是二&#xff09;&#xff0c;价值不同&#xff0c;放的东西的价值之和最大是多少 原题&#xff1a; 解题思路&#xff1a; 看看数据就知道DP会MLE&#xff0c;所以要用排序来做&#xff0c;…

从明面上学习ASP.NET Core

一、前言这篇文章就是从能看到地方去学习Core&#xff0c;没有很深奥&#xff0c;也没有很难懂&#xff0c;现在我们开始吧。二、构建项目&#xff0c;引发思考创建项目的步骤真的很简单&#xff0c;你要是不会&#xff0c;我真也没法了&#xff0c;我这是创建的MVC的项目。接下…