dsu on tree 与长链剖分
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 与长链剖分的更多相关文章
- CF1009F Dominant Indices(树上DSU/长链剖分)
题目大意: 就是给你一棵以1为根的树,询问每一个节点的子树内节点数最多的深度(相对于这个子树根而言)若有多解,输出最小的. 解题思路: 这道题用树链剖分,两种思路: 1.树上DSU 首先想一下最暴力的 ...
- 2018牛客网暑假ACM多校训练赛(第七场)I Tree Subset Diameter 动态规划 长链剖分 线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round7-I.html 题目传送门 - https://www.n ...
- BZOJ 3653: 谈笑风生(离线, 长链剖分, 后缀和)
题意 给你一颗有 \(n\) 个点并且以 \(1\) 为根的树.共有 \(q\) 次询问,每次询问两个参数 \(p, k\) .询问有多少对点 \((p, a, b)\) 满足 \(p,a,b\) 为 ...
- 【CF1009F】Dominant Indices(长链剖分)
[CF1009F]Dominant Indices(长链剖分) 题面 洛谷 CF 翻译: 给定一棵\(n\)个点,以\(1\)号点为根的有根树. 对于每个点,回答在它子树中, 假设距离它为\(d\)的 ...
- 【Cf Edu #47 F】Dominant Indices(长链剖分)
要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来. 参考重链剖分,由于一个点向上最多只有$log$条轻边,故 ...
- CF 1009 F Dominant Indices —— 长链剖分+指针
题目:http://codeforces.com/contest/1009/problem/F 也可以用 dsu on tree 的做法,全局记录一个 dep,然后放进堆里,因为字典序要最小,所以再记 ...
- 长链剖分优化dp三例题
首先,重链剖分我们有所认识,在dsu on tree和数据结构维护链时我们都用过他的性质. 在这里,我们要介绍一种新的剖分方式,我们求出这个点到子树中的最长链长,这个链长最终从哪个儿子更新而来,那个儿 ...
- BZOJ4543/BZOJ3522 [POI2014]Hotel加强版(长链剖分)
题目好神仙--这个叫长链剖分的玩意儿更神仙-- 考虑dp,设\(f[i][j]\)表示以\(i\)为根的子树中到\(i\)的距离为\(j\)的点的个数,\(g[i][j]\)表示\(i\)的子树中有\ ...
- CF1009F Dominant Indices——长链剖分优化DP
原题链接 \(EDU\)出一道长链剖分优化\(dp\)裸题? 简化版题意 问你每个点的子树中与它距离为多少的点的数量最多,如果有多解,最小化距离 思路 方法1. 用\(dsu\ on\ tree\)做 ...
随机推荐
- caffe 安装
安装caffe 拉取镜像 nvidia/cuda:9.0-cudnn7-devel-centos7 1,换源 安装https://blog.csdn.net/tuomen5867/article/de ...
- ThoughtWorks.QRCode 生成二维码名片(实现二维码内容换行)
最近在写一个很简单的功能,按照Vcard的格式,生成二维码名片.本来以为分分钟完事的事情,替换数据,直接调用dll去生成二维码. 测试时,发现生成的二维码使用微信扫描得到的名片信息为空,反向解析发现, ...
- max pool实现
题目 二维矩阵(nm) 求每个(lw)的子矩阵的最大元素, 就是一维滑动窗口的升级版 自己瞎掰的题解 #include <bits/stdc++.h> using namespace st ...
- ModelSerializer 使用知识点_serializer.save(project=obj) #外键一定要作为实例传入save函数,否则无法新增成功
1.有两个模型如下 A.project class Project(models.Model): """ 项目表 """ id = mode ...
- [BZOJ2560]串珠子:状压DP+容斥原理
分析 为什么我去年6月做过这道题啊,估计当时抄的题解. 具体做法就是令\(f[S]\)表示保证连通点集\(S\)的方案数,\(g[S]\)表示不保证连通点集\(S\)的方案数. 容易想到: \[g[S ...
- kibana花式查询
在kibana提供的界面上进行操作. POST /school/student/_bulk{ "index": { "_id": 1 }}{ "nam ...
- 如何下载如腾讯课堂等PC网页视频的方法
其实网上的教程有很多,实际也没那么复杂. 一.用插件法 方法是用插件,大多数主流的浏览器都是支持插件的,只要下载个插件应用市场的视频插件就可以搞定了. 当然,每个浏览器的视频插件品牌都是不一样的.这里 ...
- android存储路径问题
关于存储路径问题,如果是想要存储在应用本身的路径下,如果该应用卸载的时候,对应文件随之卸载, 如果使用的是android level 8以上的版本,采用的是: getExternalFilesDir( ...
- 安装mariadb报错: Job for mariadb.service failed because the control process exited with error code. See "systemctl status mariadb.service" and "journalctl -xe" for details.
卸载和删除都使用过了,没有起到效果,然后用了如下的方案,进行解决: CentOS 从 Yum 源安装配置 Mariadb 2017.03.01 WangYan 学习笔记 热度 7℃ 一.安装 Mar ...
- POJ 1625 Censored ( Trie图 && DP && 高精度 )
题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种? 分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中 ...