例题:

一棵n个节点的树,m次查询,每次查询给你一个点集U,对于树上的所有节点x(x∉U),你要找到一个点y(y∈U)满足y点离x点最近且标号最小,表示x点受y点管辖,而你的任务就是对于每次查询输出U集合中的每个点各管辖多少点

n<=300000,m<=300000,∑xi<=300000

m次查询,每次遍历整棵树显然不可能,但是从上面蓝色的条件可以得知平均每次询问的点是非常少的

这样的话考虑每次只遍历询问的点复杂度就会从O(nm)到O(∑xi)大幅降低

问题就是如何将询问的点拉出来,看下图

其中红色点为当前查询的点,下面有红线的点是其中某一对红点的LCA

把下面有红线的点和红点拉出来可以得出一棵树,就是虚树

所以我们只要每次查询把虚树拉出来然后求就可以降低一维的复杂度

虽然虚树中多了很多LCA,但是可以证明这些“额外”点的数量平均不会超过一倍,所以对复杂度无影响

主要是如何求出虚树

步骤:

①求出所有点的dfs序和深度d[],并对整棵树进行倍增LCA的预处理

②对于每次查询,用一个栈维护,按照dfs序遍历当次查询的所有点

③对于当前点x,如果栈顶节点y不是x的祖先,弹出栈顶y,father[y] = lca(y, x)(前提y点的father[]深度比lca小)

直到栈顶节点是x祖先结束

④这个时候y一定是x祖先,如果y!=lca(y, x),那么lca(y, x)一定也是虚树中的节点(对应上图中底下画红线的节点),将其加入虚树中,并加入栈中,它的父亲就是y

⑤将当前点x加入栈中,它的父亲为lca(y, x),继续执行步骤③直到所有节点遍历结束

到这里虚树就求出来了,就变成一道普通的题了,再想怎么求出答案

t[]:里面存的全部都是虚树中的点

g[p] = (x, y):x是权值,y是离p最近的管辖点,x是距离,其中p一定是虚树中的点,和t[]对应

fa[]:虚树中每个点的父亲

w[p]:虚树中p点和它父亲之间的距离

考虑树形DP:

①对于虚树中的所有点,先求出离它最近的管辖点,当然很多情况都是它本身

(别忘了有LCA,所以虚树中并不是所有点都是管辖点,具体求法见代码)

然后DFS整棵虚树,因为已经是按dfs序排好了,所以直接遍历就相当于DFS了

求出虚树中每条边对答案的贡献就好了,例如上面的图,求出边E(14, 18)对答案的贡献就相当于求原树中点17对答案的贡献,当然求完之后会漏掉一些点(例如点3, 6, 8, 9, 15全部都会被漏掉)但这些点非常好办不是么,它们一定属于离它最近的管辖点

3572: [Hnoi2014]世界树

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1852  Solved: 981
[Submit][Status][Discuss]

Description

世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为1。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;例如,若聚居地a和b之间有道路,b和c之间有道路,因为每条道路长度为1而且又不可能出现环,所卧a与c之间的距离为2。
出于对公平的考虑,第i年,世界树的国王需要授权m[i]个种族的聚居地为临时议事处。对于某个种族x(x为种族的编号),如果距离该种族最近的临时议事处为y(y为议事处所在聚居地的编号),则种族x将接受y议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则y为其中编号最小的临时议事处)。
现在国王想知道,在q年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

Input

第一行为一个正整数n,表示世界树中种族的个数。
接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双
向道路。接下来一行为一个正整数q,表示国王询问的年数。
接下来q块,每块两行:
第i块的第一行为1个正整数m[i],表示第i年授权的临时议事处的个数。
第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被授权为临时议事处的聚居地编号(保证互不相同)。

Output

输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。

Sample Input

10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8

Sample Output

1 9
3 1 4 1 1
10
1 1 3 5
4 1 3 1

就是上面的例题

#include<stdio.h>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
vector<int> G[300005];
pair<int, int> g[300005];
int Time, n, m, ec, f[300005][20], dfn[300005], size[300005], d[300005];
int h[300005], id[300005], st[300005], father[300005], t[300005], val[300005], ans[300005], w[300005];
bool comp(int x, int y)
{if(dfn[x]<dfn[y])return 1;return 0;
}
void Sech(int u)
{int i, v, j;dfn[u] = ++Time;size[u] = 1;for(i=0;i<G[u].size();i++){v = G[u][i];if(v==f[u][0])continue;f[v][0] = u;for(j=0;f[f[v][j]][j]!=0;j++)f[v][j+1] = f[f[v][j]][j];d[v] = d[u]+1;Sech(v);size[u] += size[v];}
}
int Find(int u, int dep)
{int i;for(i=19;i>=0;i--){if(d[f[u][i]]>=dep)u = f[u][i];}return u;
}
int LCA(int u, int v)
{int i;if(d[u]<d[v])swap(u, v);for(i=19;i>=0;i--){if(d[f[u][i]]>=d[v])u = f[u][i];}if(u==v)return u;for(i=19;i>=0;i--){if(f[u][i]!=f[v][i])u = f[u][i], v = f[v][i];}return f[u][0];
}
int main(void)
{int x, y, i, q, m, cnt, top, p, lca, fa, sum, mid;scanf("%d", &n);for(i=1;i<=n-1;i++){scanf("%d%d", &x, &y);G[x].push_back(y);G[y].push_back(x);}scanf("%d", &q);d[1] = 1;Sech(1);while(q--){cnt = 0;scanf("%d" ,&m);for(i=1;i<=m;i++){scanf("%d", &h[i]);t[++cnt] = id[i] = h[i];g[h[i]] = make_pair(0, h[i]);ans[h[i]] = 0;}top = 0;sort(h+1, h+m+1, comp);for(i=1;i<=m;i++){if(top==0){st[++top] = h[i];father[st[top]] = 0;}else{lca = LCA(h[i], st[top]);for(;d[st[top]]>d[lca];top--){if(d[st[top-1]]<=d[lca])father[st[top]] = lca;}if(st[top]!=lca){t[++cnt] = lca;g[lca] = make_pair(1044266558, 0);father[lca] = st[top];st[++top] = lca;}father[h[i]] = lca;st[++top] = h[i];}}sort(t+1, t+cnt+1, comp);for(i=1;i<=cnt;i++){p = t[i];val[p] = size[p];if(i>1)w[p] = d[p]-d[father[p]];}for(i=cnt;i>=2;i--){p = t[i];fa = father[p];g[fa] = min(make_pair(g[p].first+w[p], g[p].second), g[fa]);}for(i=2;i<=cnt;i++){p = t[i];fa = father[p];g[p] = min(make_pair(g[fa].first+w[p], g[fa].second), g[p]);}for(i=1;i<=cnt;i++){p = t[i];fa = father[p];if(i==1)ans[g[p].second] += n-size[p];else{x = Find(p, d[fa]+1);sum = size[x]-size[p];val[fa] -= size[x];if(g[fa].second==g[p].second)ans[g[p].second] += sum;else{mid = d[p]+g[p].first-(g[fa].first+g[p].first+w[p])/2;if((g[fa].first+g[p].first+w[p])%2==0 && g[p].second>g[fa].second)++mid;y = size[Find(p, mid)]-size[p];ans[g[p].second] += y;ans[g[fa].second] += sum-y;}}}for(i=1;i<=cnt;i++)ans[g[t[i]].second] += val[t[i]];for(i=1;i<=m;i++)printf("%d ", ans[id[i]]);puts("");}return 0;
}

虚树(bzoj 3572: [Hnoi2014]世界树)相关推荐

  1. bzoj 3572 [Hnoi2014]世界树——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3572 关于虚树:https://www.cnblogs.com/zzqsblog/p/556 ...

  2. bzoj 3572: [Hnoi2014]世界树

    Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持 ...

  3. bzoj3572世界树 虚树+树型动规

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec   Memory Limit: 512 MB Submit: 1786   Solved: 957 [ Submit][ ...

  4. BZOJ3572: [Hnoi2014]世界树

    题解: 首先建出一颗虚树  对于虚树上的每个节点DP找出离得最近的关键节点的编号和距离 然后考虑一遍dfs 对于每条链上子树 我们倍增找到mid位置 然后mid以下的属于下面节点 mid以上的属于上面 ...

  5. 「HNOI2014」世界树 虚树

    「HNOI2014」世界树 前置技能:虚树. (本题可以通过以下相似的思想用线段树维护子树信息和倍增找中点完成,代码短很多,但本篇题解不涉及) 题解部分 这种总询问点数不大,但是询问次数多,可以想到用 ...

  6. BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】

    题目 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. ...

  7. [HNOI2014]世界树 (虚树DP+倍增)

    世界树 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石 ...

  8. bzoj3572 [HNOI2014]世界树 虚树 +乱dp

    这个题有Σ的条件,肯定还是用log结构求询问点相关了 但这个题是点之间的距离关系,所以本来想用中点来代替原来的lca,但中点的个数不满足任何单调性,而且个数也不是n个 所以还是要用lca,所以考虑lc ...

  9. 【HNOI2014】世界树(worldtree) (虚树详解)

    题目大意 原题又臭又长,总之简介来说的话就是 给定一棵树,有若干个询问,每次给定m个点,每个点都被这m个点中最近(距离相同,编号小的近)的点管辖.问m个点分别管几个点. n<=300000,q& ...

最新文章

  1. 用SimpleDateFormat类设置时间格式
  2. 5中打开safari_iOS13版Safari浏览器新功能上线:可调节上传照片大小
  3. PB中如何调用shellExecute
  4. Mybatis的下载并搭建核心架构
  5. 抽象类和接口的共同点和区别
  6. 输入字符串统计字符串中每个字符出现的次数
  7. docker: Error response from daemon: driver failed programming external connectivity
  8. 从0开始学java视频_Java全套学习视频放送,从零开始一步步掌握Java技能!
  9. cocos2dx setVisible 与setEnabled 小实例
  10. asp小偷转html,ASP “小偷”程序(抓取程序)
  11. 掘金企服:ICP经营许可证和ICP备案的区别
  12. hex文件分析+Qt5制作Hex文件转Bin文件的工具(含源码+工具下载)
  13. 为游戏多开做准备,降低游戏的CPU
  14. 每日技巧分享:怎么裁剪音频,快学习起来
  15. HDS设备高级操作_VSP_更换Cache电池手册
  16. 【踩坑】python: This install of SoX cannot process .mp3 files
  17. 在html中frame标签的作用,HTML中的frame标签常见的6大属性,新手一定要悉知!
  18. 腾讯股票实时数据接口
  19. TAD2141 角度传感器使用SPI:数据手册略读
  20. 地球罕见的九大自然现象

热门文章

  1. 零基础自学python-零基础如何自学python?
  2. 一张图学会python应用到excel-Python应用之------Excel操作
  3. python工程师工资多少-Python全栈工程师为何这么火薪资这么高看了才知道
  4. 浅谈语音识别技术的发展趋势与应用前景 - 全文
  5. ios12 siri 语音识别
  6. 计算机典型的操作系统有,计算机操作系统典型示例.doc
  7. 前端工程化(ES6模块化和webpack打包)
  8. 【黑马JS笔记】JavaScript基础语法
  9. linux c程序hello,Linux下实现c语言hello world 步骤
  10. linux tomcat 配置数据库,tomcat把项目放在root下root.xml配置数据库