这个算法还是挺人性化的,没有什么难度 就是可能看起来有点晕什么的。

大体 思想是 利用重链刨分来优化子树内部的查询。

考虑一个问题要对每个子树都要询问一次。我们暴力显然是\(n^2\)的。

考虑一下优化这个过程,我们发现儿子的信息可以给父亲用但是不能给兄弟或兄弟里的儿子用。

如果是最大最小值我们只能暴力来搞 但如果是出现次数什么的我们可以利用捅差分来解决这个事情。

考虑我们每次先暴力扫轻儿子然后 再做重儿子然后再把轻儿子的代价加上算当前节点的代价然后再把轻儿子的代价给删掉。

我们发现轻儿子被加上删掉两次 而重儿子只做一次并且保留。

可以发现这样做的复杂度很低 考虑一个点到根有logn条轻边所以这样最坏一个点被暴力来回扫logn次 统计自身答案的时候被扫了1次。

最终复杂度为nlogn 说起来很容易但其实代码还是存在一些细节的 要想好再写。

例题:CF600ELomsat gelral

const int MAXN=100010;
int n,len,mx;
int a[MAXN],cnt[MAXN],root[MAXN],sz[MAXN],son[MAXN];
int lin[MAXN],nex[MAXN<<1],ver[MAXN<<1];ll ans[MAXN],w;
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline void dfs(int x,int father)
{
sz[x]=1;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father)continue;
dfs(tn,x);
sz[x]+=sz[tn];
if(sz[son[x]]<sz[tn])son[x]=tn;
}
}
inline void update(int x,int father,int op,int target)
{
cnt[a[x]]+=op;
if(op>0&&cnt[a[x]]>=mx)
{
if(cnt[a[x]]==mx)w+=a[x];
else w=a[x],mx=cnt[a[x]];
}
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father||tn==target)continue;
update(tn,x,op,target);
}
}
inline void dfs(int x,int father,int op)
{
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father||tn==son[x])continue;
dfs(tn,x,0);//处理轻儿子的答案且清除
}
if(son[x])dfs(son[x],x,1);//处理重儿子的答案
update(x,father,1,son[x]);//把轻儿子的代价加入
ans[x]=w;//答案
if(!op)update(x,father,-1,0),w=0,mx=0;//当前是轻儿子所以删掉
}
int main()
{
freopen("1.in","r",stdin);
n=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<n;++i)
{
int x,y;
x=read();y=read();
add(x,y);add(y,x);
}
dfs(1,0);
dfs(1,0,1);
for(int i=1;i<=n;++i)printf("%lld ",ans[i]);
return 0;
}

虽然这道题可以使用线段树合并来做但是那样对空间和时间的花销都是nlogn的 所以dsu on tree在空间上要优于线段树合并。

且 常数上也必然小于线段树合并。

我们只是关注与dsu on tree的思想 使用重链刨分来进行优化。

再来一道简单的题目来简单再看一下:CF208E Blood Cousins

求有多少个点和某个点的K级祖先相同。不难想到先求出K级祖先然后求出K级祖先子树内深度为x的点的个数。

关于K级祖先的求法:可以倍增+长链刨分优化实现O(1)但是仅对这道题就没什么必要了 询问和n同阶。

可以直接倍增搞,我们还有更快的方法:离线 我们dfs一个点然后加到栈中我们维护某条链上的点。

询问直接查栈中的从前往后第K个元素即可。

考虑第二问 求子树内深度为x的点的个数。显然 dsu on tree。

当然可以使用线段树合并,还有更快的方法:离线 开捅统计对于询问进行捅内外的差分。综上这道题被离线干成了O(n).

为了学习dsu on tree这里使用dsu on tree.

这道题 离线大法好 又得到了一个求树上K级祖先的方法 离线开栈。

const int MAXN=100010;
int n,len,mx,tot,top,m;
int a[MAXN],s[MAXN],cnt[MAXN],root[MAXN],sz[MAXN],son[MAXN];
int lin[MAXN],nex[MAXN],ver[MAXN],d[MAXN],ans[MAXN];
vector<pii>g[MAXN],w[MAXN];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline void dfs(int x,int father)
{
d[x]=d[father]+1;sz[x]=1;
s[++top]=x;
for(int i=0;i<g[x].size();++i)
{
int tn=g[x][i].F;
if(tn>d[father])continue;
int ss=s[top-tn];
w[ss].push_back(mk(d[x],g[x][i].S));
}
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father)continue;
dfs(tn,x);
sz[x]+=sz[tn];
if(sz[son[x]]<sz[tn])son[x]=tn;
}
--top;
}
inline void update(int x,int father,int op,int target)
{
cnt[d[x]]+=op;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father||tn==target)continue;
update(tn,x,op,target);
}
}
inline void dfs(int x,int father,int op)
{
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(tn==father||tn==son[x])continue;
dfs(tn,x,0);
}
if(son[x])dfs(son[x],x,1);
update(x,father,1,son[x]);
for(int i=0;i<w[x].size();++i)
ans[w[x][i].S]+=cnt[w[x][i].F];
if(!op)update(x,father,-1,0);
}
int main()
{
freopen("1.in","r",stdin);
n=read();
for(int i=1;i<=n;++i)
{
int x=read();
if(!x)root[++tot]=i;
else add(x,i);
}
m=read();
for(int i=1;i<=m;++i)
{
int x,y;
x=read();y=read();
g[x].push_back(mk(y,i));
}
for(int i=1;i<=tot;++i)dfs(root[i],0);
for(int i=1;i<=tot;++i)dfs(root[i],0,0);//dsu on tree
rep(1,m,i)printf("%d ",ans[i]?ans[i]-1:0);
return 0;
}

dsu on tree详解的更多相关文章

  1. [CF1009F] Dominant Indices (+dsu on tree详解)

    这道题用到了dsu(Disjoint Set Union) on tree,树上启发式合并. 先看了CF的官方英文题解,又看了看zwz大佬的题解,差不多理解了dsu on tree的算法. 但是时间复 ...

  2. 【算法】关于图论中的最小生成树(Minimum Spanning Tree)详解

    本节纲要 什么是图(network) 什么是最小生成树 (minimum spanning tree) 最小生成树的算法 什么是图(network)? 这里的图当然不是我们日常说的图片或者地图.通常情 ...

  3. 二叉查找树(binary search tree)详解

    二叉查找树(Binary Search Tree),也称二叉排序树(binary sorted tree),是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有结点的值均小于 ...

  4. BTree和B+Tree详解

    https://www.cnblogs.com/vianzhang/p/7922426.html B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引.B+树中的B代表平 ...

  5. ODT(old driver tree)详解(带例题)

    文章目录 ODT简介 实现前提&&实现原理 初始化 split操作 assign操作 其它操作 区间第k小 区间加 区间所有数的k次方和 几道水题 ODT简介 ODT(old driv ...

  6. 数据结构31:树(Tree)详解

    复制广义表数据结构中的树 树是数据结构中比较重要也是比较难理解的一类存储结构.本章主要主要围绕二叉树,对树的存储以及遍历做详细的介绍,同时还会涉及到有关树的实际应用,例如构建哈弗曼编码等. 由于树存储 ...

  7. 【2018.9.26】K-D Tree详解

    网上对K-D-Tree的讲解不尽清晰,我学了很久都不会写,这里新开一文做一些讲解. 1.K-D-Tree是什么? K-DTree 即 K-Dimensional-Tree,常用来作空间划分及近邻搜索, ...

  8. dsu on tree (树上启发式合并) 详解

    一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...

  9. Ext.Net学习笔记22:Ext.Net Tree 用法详解

    Ext.Net学习笔记22:Ext.Net Tree 用法详解 上面的图片是一个简单的树,使用Ext.Net来创建这样的树结构非常简单,代码如下: <ext:TreePanel runat=&q ...

随机推荐

  1. 如何让touchmove之后不触发touchend的事件

    手机扫码看效果 不多说,直接上代码 <ul id="Ul"> <li>111</li> <li>222</li> < ...

  2. flask 源码专题(二):请求上下文与全文上下文

    源码解析 0. 请求入口 if __name__ == '__main__': app.run() def run(self, host=None, port=None, debug=None, lo ...

  3. 数据可视化之PowerQuery篇(十五)如何使用Power BI计算新客户数量?

    https://zhuanlan.zhihu.com/p/65119988 每个企业的经营活动都是围绕着客户而开展的,在服务好老客户的同时,不断开拓新客户是每个企业的经营目标之一. 开拓新客户必然要付 ...

  4. 也来谈谈python编码

    一.coding:utf-8 让我们先来看一个示例,源码文件是utf-8格式: print('你好 python') 当使用python2执行该程序时会收到一下报错: File "./hel ...

  5. Log4net控制台和窗体程序无法输出记录的原因之一

    在asp.net web应用程序中,读取log4net的配置文件可以这样写: [assembly:log4net.Config.XmlConfigurator(ConfigFile="Web ...

  6. 使用pycharm、跳板机连接内网服务器

    使用pycharm.跳板机连接内网服务器 接手实验室服务器后,大部分同学在GPU集群上跑程序都是直接在ssh界面上跑,这里想着通过pycharm通过跳板机来连接服务器. 总体就是实验室服务器仅限内网访 ...

  7. 动手实现 LRU 算法,以及 Caffeine 和 Redis 中的缓存淘汰策略

    我是风筝,公众号「古时的风筝」. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 那天我在 LeetCode 上刷到一道 LRU 缓存机制的问题, ...

  8. js自定义获取浏览器宽高

    /** * @description js自定义获取浏览器宽高 * * IE8 和 IE8 以下的浏览器不兼容 * window.innerWidth * window.innerHeight * * ...

  9. Go Pentester - TCP Proxy

    Building a TCP Proxy Using io.Reader and io.Writer Essentially all input/output(I/O). package main i ...

  10. [翻译]ASP.NET Core在 .NET 5 Preview 7的更新

    .NET 5 Preview 7现在可以用了,可以进行评估了.这是此版本中的新增功能: Blazor WebAssembly应用程序现在针对.NET 5 更新了Blazor WebAssembly的调 ...