dsu on tree

对于树进行轻重链剖分,对于节点 $x$ ,递归所有轻儿子后消除其影响,递归重儿子,不消除其影响。

然后对于所有轻儿子的子树暴力,从而得到 $x$ 的答案。

对于要消除暴力消除即可。

可以发现如果暴力到点 $u$ 必然是其 $u$ 到根的轻边数量,从而时间复杂度除在统计每个节点答案时其余时间复杂度为 $O(n\log n)$ 。

CF 600E Lomsat gelral

模板题,按上述过程模拟即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
const int MAXN=;
struct node{
int u,v,nex;
}x[MAXN<<];
int head[MAXN],cnt,N,A[MAXN];
void add(int u,int v){
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
int Cnt[MAXN],Mx,sum,Ans[MAXN],V,siz[MAXN],son[MAXN];
void dfs(int u,int fath){
siz[u]=;
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
dfs(x[i].v,u);siz[u]+=siz[x[i].v];
if(siz[son[u]]<siz[x[i].v]) son[u]=x[i].v;
}return;
}
void dfs1(int u,int fath,int w){
Cnt[A[u]]+=w;
if(Cnt[A[u]]>Mx) Mx=Cnt[A[u]],sum=A[u];
else if(Cnt[A[u]]==Mx) sum+=A[u];
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath||x[i].v==V) continue;
dfs1(x[i].v,u,w);
}return;
}
void dfs(int u,int fath,int opt){
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath||x[i].v==son[u]) continue;
dfs(x[i].v,u,);
}
if(son[u]) dfs(son[u],u,);
V=son[u];dfs1(u,fath,);
Ans[u]=sum;
if(!opt) V=,dfs1(u,fath,-),Mx=sum=;
}
signed main(){
memset(head,-,sizeof(head));
N=read();
for(int i=;i<=N;i++) A[i]=read();
for(int i=;i<N;i++){
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs(,);dfs(,,);
for(int i=;i<=N;i++) printf("%lld ",Ans[i]);printf("\n");
return ;
}

或者可以线段树合并,利用线段树维护颜色个数。

CF 1009F Dominant Indices

可以长链剖分也可以 $dsu$ ,$dsu$ 的时间复杂度 $O(n\log n)$ 。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int MAXN=;
struct node{
int u,v,nex;
}x[MAXN<<];
int dep[MAXN],cnt,siz[MAXN],son[MAXN],N,head[MAXN];
int Ans[MAXN];
void add(int u,int v){
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
void dfs0(int u,int fath){
siz[u]=;dep[u]=dep[fath]+;
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
dfs0(x[i].v,u);siz[u]+=siz[x[i].v];
if(siz[son[u]]<siz[x[i].v]) son[u]=x[i].v;
}return;
}
int Num[MAXN],Mx,Sum,Lim;
void Add(int u,int fath,int w){
Num[dep[u]]+=w;
if(Num[dep[u]]>Mx) Mx=Num[dep[u]],Sum=dep[u];
else if(Num[dep[u]]==Mx&&dep[u]<Sum) Sum=dep[u];
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath||x[i].v==Lim) continue;
Add(x[i].v,u,w);
}return;
}
void dfs1(int u,int fath,int opt){
// cerr<<u<<" "<<fath<<" "<<opt<<endl;
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath||x[i].v==son[u]) continue;
dfs1(x[i].v,u,);
}
if(son[u]) dfs1(son[u],u,);Lim=son[u];
Add(u,fath,);Ans[u]=Sum;
Lim=;
if(!opt) Add(u,fath,-),Mx=Sum=;
return;
}
int main(){
// freopen("maker.in","r",stdin);
memset(head,-,sizeof(head));
N=read();
for(int i=;i<N;i++){int u=read(),v=read();add(u,v),add(v,u);}
dfs0(,);dfs1(,,);
for(int i=;i<=N;i++){
printf("%d\n",Ans[i]-dep[i]);
}
return ;
}/*
8
1 2
2 3
1 4
3 5
4 6
5 7
4 8
*/

长链剖分

对于重儿子为 $u$ 下面最深的链所在儿子,可以发现最多到根有 $\sqrt{n}$ 个长链与短链,因为对于每次走到轻边必加上比他深的儿子,可以写成 $1+2+…x=n->x=\sqrt{n}$ 。

如果一个子树 $dp$ 只与深度有关,则可能可以使用长链剖分的方法优化它的复杂度。

详细情况请参考 $link$ 。考虑对于继承每个重儿子的话可以用指针维护,或者数组映射即可。

CF 1009F Dominant Indices

虽然可以 $dsu$ ,但是通过长链剖分可以得到更优的复杂度 $O(n)$ 。时间复杂度为 $O(n)$ 因为每条重链只统计一次。

「POI2014」酒店 Hotel

$n\leq 10^5$ 。考虑 $O(n^2)$ 的树形 $dp$ ,设 $f_{i,j}$ 表示在以 $i$ 为根的子树下到 $i$ 距离为 $j$ 的点的个数,$g_{i,j}$ 表示在以 $i$ 为根的子树上有多少个点对需要经过 $i$ 号点后再走 $j$ 步。

转移考虑当前子树对另一颗子树的贡献与自己的贡献即可。可以发现 $dp$ 的第二维只与深度有关,并且支持合并,长链剖分即可。

一个小建议就是空间可以多开一点。

[WC2010] 重建计划

可以发现将答案二分以后分数规划问题就转换成边数在 $[l,r]$ ,且边权和大于等于 $0$ 是否有解。

考虑将点对答案在 $lca$ 处处理,维护 $f_{i,j}$ 表示以 $i$ 为根的子树下到 $i$ 经过 $j$ 条边的最大边权。而需要做的是 $f$ 一段区间的 $max$ 。

很显然 $f$ 数组支持长链剖分,而 $max$ 操作无法通过指针维护,考虑利用数组映射,同时建线段树维护极值。

dsu on tree 与长链剖分的更多相关文章

  1. CF1009F Dominant Indices(树上DSU/长链剖分)

    题目大意: 就是给你一棵以1为根的树,询问每一个节点的子树内节点数最多的深度(相对于这个子树根而言)若有多解,输出最小的. 解题思路: 这道题用树链剖分,两种思路: 1.树上DSU 首先想一下最暴力的 ...

  2. 2018牛客网暑假ACM多校训练赛(第七场)I Tree Subset Diameter 动态规划 长链剖分 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round7-I.html 题目传送门 -  https://www.n ...

  3. BZOJ 3653: 谈笑风生(离线, 长链剖分, 后缀和)

    题意 给你一颗有 \(n\) 个点并且以 \(1\) 为根的树.共有 \(q\) 次询问,每次询问两个参数 \(p, k\) .询问有多少对点 \((p, a, b)\) 满足 \(p,a,b\) 为 ...

  4. 【CF1009F】Dominant Indices(长链剖分)

    [CF1009F]Dominant Indices(长链剖分) 题面 洛谷 CF 翻译: 给定一棵\(n\)个点,以\(1\)号点为根的有根树. 对于每个点,回答在它子树中, 假设距离它为\(d\)的 ...

  5. 【Cf Edu #47 F】Dominant Indices(长链剖分)

    要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来. 参考重链剖分,由于一个点向上最多只有$log$条轻边,故 ...

  6. CF 1009 F Dominant Indices —— 长链剖分+指针

    题目:http://codeforces.com/contest/1009/problem/F 也可以用 dsu on tree 的做法,全局记录一个 dep,然后放进堆里,因为字典序要最小,所以再记 ...

  7. 长链剖分优化dp三例题

    首先,重链剖分我们有所认识,在dsu on tree和数据结构维护链时我们都用过他的性质. 在这里,我们要介绍一种新的剖分方式,我们求出这个点到子树中的最长链长,这个链长最终从哪个儿子更新而来,那个儿 ...

  8. BZOJ4543/BZOJ3522 [POI2014]Hotel加强版(长链剖分)

    题目好神仙--这个叫长链剖分的玩意儿更神仙-- 考虑dp,设\(f[i][j]\)表示以\(i\)为根的子树中到\(i\)的距离为\(j\)的点的个数,\(g[i][j]\)表示\(i\)的子树中有\ ...

  9. CF1009F Dominant Indices——长链剖分优化DP

    原题链接 \(EDU\)出一道长链剖分优化\(dp\)裸题? 简化版题意 问你每个点的子树中与它距离为多少的点的数量最多,如果有多解,最小化距离 思路 方法1. 用\(dsu\ on\ tree\)做 ...

随机推荐

  1. opencv加椒盐噪声

    void salt(IplImage *img, int saltNum) { int x,y; int i ; unsigned char *src = NULL; src = (unsigned ...

  2. UVa 122 Trees on the level (动态建树 && 层序遍历二叉树)

    题意  :输入一棵二叉树,你的任务是按从上到下.从左到右的顺序输出各个结点的值.每个结 点都按照从根结点到它的移动序列给出(L表示左,R表示右).在输入中,每个结点的左 括号和右括号之间没有空格,相邻 ...

  3. 监听ios自带返回功能

    //1.一开始用这段代码,结果发现滚动都失效了,如果页面大于屏幕高度将无法滚动至底部,所以淘汰 // document.addEventListener('touchmove', function(e ...

  4. pycharm的个性化设置

    1. 调整背景颜色 file -- settings -- Editor -- Color Scheme 2. 调整字体.字号.行间距 file -- settings -- Editor -- Fo ...

  5. Redis高级命令及特性(安全性)

    高级命令 ​ keys * : 返回满足的所有键 ,可以模糊匹配 ​ exists :是否存在指定的key,存在返回1,不存在返回0 ​ exprie:设置某个key的过期时间 ​ ttl:查看剩余时 ...

  6. java中 Excel表实现数据导入导出

    需要引入依赖: <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> < ...

  7. socket的补充

  8. Loading class `com.mysql.jdbc.Driver'. This is deprecated警告处理,jdbc更新处

    1.报错信息是这样的; 处理:提示信息表明数据库驱动com.mysql.jdbc.Driver'已经被弃用了.应当使用新的驱动com.mysql.cj.jdbc.Driver' 所以,按照提示更改jd ...

  9. 使用Zabbix通过ILO管理口监控惠普服务器

    https://blog.csdn.net/qq_41571056/article/details/82928542

  10. Mysql 创建函数出现This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA

    This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary mys ...