CF1009F Dominant Indices(树上DSU/长链剖分)
题目大意:
就是给你一棵以1为根的树,询问每一个节点的子树内节点数最多的深度(相对于这个子树根而言)若有多解,输出最小的。
解题思路:
这道题用树链剖分,两种思路:
1.树上DSU
首先想一下最暴力的算法:统计子树每个深度节点的个数(桶)相当于以每个节点为根遍历子树搜索一遍答案,这样做时间复杂度是O(n2),显然过不去。
考虑一下优化。假如说我们模拟一下搜索答案的过程,我们发现在每一次暴搜时都会在桶中添加一些答案。而这些答案的整体只会对该节点及其祖先产生贡献,也就是说,只有该节点以及其祖先的桶中才一定会有这个答案的整体,也只会对该节点及以下非同祖子树答案产生干扰。也就是说,搜索一棵树时,其答案可以直接加到其祖先上,所以对于最后一颗子树,因为之后不会再干扰其他子树所以其答案可以直接上传至父节点。那么这个最后搜索的节点的子树应该越大越好,那么就可以使用树链剖分解决了。答案更新时,最后搜最大的即可。
对于时间复杂度,每次搜索最坏为O(n),最大儿子上传是O(1),小儿子上传为O(n),轻儿子log2n个所以时间复杂度为O(logn)
上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
struct pnt{
int hd;
int dp;
int wgt;
int mxs;
int ans;
}p[];
struct ent{
int twd;
int lst;
}e[];
struct pr{
int x,y;
bool friend operator == (pr a,pr b){return (a.x==b.x)&&(a.y==b.y);}
bool friend operator > (pr a,pr b){if(a.y==b.y)return a.x<b.x;return a.y>b.y;}
bool friend operator < (pr a,pr b){if(a.y==b.y)return a.x>b.x;return a.y<b.y;}
bool friend operator <= (pr a,pr b){return ((a<b)||(a==b));}
bool friend operator >= (pr a,pr b){return ((a>b)||(a==b));}
};
class Prq{
public:
bool bol(void)
{
return (bool)(siz==);
}
void maxs(int &b)
{
b=line[].x;
}
void del(void)
{
line[]=line[siz--];
int nw,nx;
nw=;
while((nw<<)<=siz)
{
nx=nw<<;
if(nx<siz&&line[nx]<line[nx+])
nx++;
if(line[nx]<=line[nw])
break;
std::swap(line[nw],line[nx]);
nw=nx;
}
return ;
}
void ins(int a,int b)
{
pr tmp=(pr){a,b};
line[++siz]=tmp;
int nx,nw;
nw=siz;
while(nw>)
{
nx=nw>>;
if(line[nx]>=line[nw])
break;
std::swap(line[nx],line[nw]);
nw=nx;
}
return ;
}
void dst(void)
{
siz=;
return ;
}
private:
pr line[];
int siz;
}Q;
int n;
int cnt;
int num[];
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
}
void Basic_dfs(int x,int f)
{
p[x].dp=p[f].dp+;
p[x].wgt=;
int maxs=-;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f)
continue;
Basic_dfs(to,x);
p[x].wgt+=p[to].wgt;
if(maxs<p[to].wgt)
{
maxs=p[to].wgt;
p[x].mxs=to;
}
}
}
void Build_dfs(int x,int f)
{
num[p[x].dp]++;
Q.ins(p[x].dp,num[p[x].dp]);
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f)
continue;
Build_dfs(to,x);
}
}
void Destory_dfs(int x,int f)
{
num[p[x].dp]--;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f)
continue;
Destory_dfs(to,x);
}
}
void DSU_dfs(int x,int f,bool hvs)
{
if(!x)
return ;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f||to==p[x].mxs)
continue;
DSU_dfs(to,x,false);
}
DSU_dfs(p[x].mxs,x,true);
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f||to==p[x].mxs)
continue;
Build_dfs(to,x);
}
num[p[x].dp]++;
Q.ins(p[x].dp,num[p[x].dp]);
Q.maxs(p[x].ans);
p[x].ans-=p[x].dp;
if(hvs)
return ;
Destory_dfs(x,f);
Q.dst();
return ;
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ade(x,y);
ade(y,x);
}
Basic_dfs(,);
DSU_dfs(,,true);
for(int i=;i<=n;i++)
printf("%d\n",p[i].ans);
return ;
}
2.树的长链剖分:
这个方法比上面的方法跑得快。
首先,观察那种最朴素的全搜一遍的O(n2)算法,它的瓶颈在于,统计答案时同一深度非同父的节点,其答案可能互相干扰,那么我们为何不合理安排内存使其答案不会互相被访问到而会同时被祖先访问到。类似于一个树链剖分序。类似长链先搜,短链后搜的剖分序。使用不同的下标索引使桶中的变量不会在深度环境下发生冲突,再logn统计答案就可以了,其实是O(nlogn)但重建部分比较简单常数较小且其最坏复杂度很难达到所以速度相当惊人。
上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
struct pnt{
int hd;
int dp;
int mxs;
bool vis;
int ind;
int ans;
int wsa;
}p[];
struct ent{
int twd;
int lst;
}e[];
int n,m;
int cnt;
int wh;
int tmp[];
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
}
void Basic_dfs(int x,int f)
{
p[x].dp=p[f].dp+;
p[x].wsa=p[x].dp;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f)
continue;
Basic_dfs(to,x);
p[x].wsa=std::max(p[x].wsa,p[to].wsa);
if(p[to].wsa>p[p[x].mxs].wsa)
{
p[x].mxs=to;
}
}
}
void Gund_dfs(int x,int f)
{
tmp[p[x].ind]=;
if(p[x].mxs)
{
p[p[x].mxs].ind=p[x].ind+;
Gund_dfs(p[x].mxs,x);
p[x].ans=p[p[x].mxs].ans+;
}
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f||to==p[x].mxs)
continue;
p[to].ind=wh;
wh+=p[to].wsa-p[to].dp+;
Gund_dfs(to,x);
for(int j=;j<=p[to].wsa-p[to].dp;j++)
{
tmp[p[x].ind+j+]+=tmp[p[to].ind+j];
if(tmp[p[x].ind+j+]>tmp[p[x].ind+p[x].ans]||(tmp[p[x].ind+j+]==tmp[p[x].ind+p[x].ans]&&p[x].ans>j+))
p[x].ans=j+;
}
}
if(tmp[p[x].ind+p[x].ans]==)
p[x].ans=;
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ade(x,y);
ade(y,x);
}
Basic_dfs(,);
wh=p[].wsa;
Gund_dfs(,);
for(int i=;i<=n;i++)
printf("%d\n",p[i].ans);
return ;
}
CF1009F Dominant Indices(树上DSU/长链剖分)的更多相关文章
- 【CF1009F】Dominant Indices(长链剖分)
[CF1009F]Dominant Indices(长链剖分) 题面 洛谷 CF 翻译: 给定一棵\(n\)个点,以\(1\)号点为根的有根树. 对于每个点,回答在它子树中, 假设距离它为\(d\)的 ...
- Codeforces 1009 F. Dominant Indices(长链剖分/树上启发式合并)
F. Dominant Indices 题意: 给一颗无向树,根为1.对于每个节点,求其子树中,哪个距离下的节点数量最多.数量相同时,取较小的那个距离. 题目: 这类题一般的做法是树上的启发式合并,复 ...
- CF1009F Dominant Indices——长链剖分优化DP
原题链接 \(EDU\)出一道长链剖分优化\(dp\)裸题? 简化版题意 问你每个点的子树中与它距离为多少的点的数量最多,如果有多解,最小化距离 思路 方法1. 用\(dsu\ on\ tree\)做 ...
- 【CF1009F】 Dominant Indices (长链剖分+DP)
题目链接 \(O(n^2)\)的\(DP\)很容易想,\(f[u][i]\)表示在\(u\)的子树中距离\(u\)为\(i\)的点的个数,则\(f[u][i]=\sum f[v][i-1]\) 长链剖 ...
- 【CF1009F】Dominant Indices(长链剖分优化DP)
点此看题面 大致题意: 设\(d(x,y)\)表示\(x\)子树内到\(x\)距离为\(y\)的点的个数,对于每个\(x\),求满足\(d(x,y)\)最大的最小的\(y\). 暴力\(DP\) 首先 ...
- CF1009F Dominant Indices 长链剖分
题目传送门 https://codeforces.com/contest/1009/problem/F 题解 长链剖分的板子吧. 令 \(dp[x][i]\) 表示 \(x\) 的子树中的深度为 \( ...
- 【Cf Edu #47 F】Dominant Indices(长链剖分)
要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来. 参考重链剖分,由于一个点向上最多只有$log$条轻边,故 ...
- CF 1009 F Dominant Indices —— 长链剖分+指针
题目:http://codeforces.com/contest/1009/problem/F 也可以用 dsu on tree 的做法,全局记录一个 dep,然后放进堆里,因为字典序要最小,所以再记 ...
- 2019.01.08 codeforces 1009F. Dominant Indices(长链剖分)
传送门 长链剖分模板题. 题意:给出一棵树,设fi,jf_{i,j}fi,j表示iii的子树中距离点iii距离为jjj的点的个数,现在对于每个点iii要求出使得fif_ifi取得最大值的那个jjj ...
随机推荐
- Android开发之Volley网络通信框架
今天用了一下Volley网络通信框架,感觉挺好用的,写个博客记录一下用法.方便以后VC. Volley(Google提供的网络通信库,能使网络通信更快,更简单,更健壮.) 功能模块: 1. JSON, ...
- 14.c语言dll注入
#include <Windows.h> //dll不需要main函数 //导出接口 _declspec(dllexport) void go() { MessageBoxA(, ); }
- BZOJ 1305 二分+网络流
思路: 建图我根本没有想到啊--. (我是不会告诉你我借鉴了一下题解的思路) 把每个人拆成喜欢的和不喜欢的点 男 喜欢 向 男 不喜欢 连 边权为k的边 如果男喜欢女 那么 男喜欢向 女喜欢 连 1 ...
- 学习推荐《从Excel到Python数据分析进阶指南》高清中文版PDF
Excel是数据分析中最常用的工具,本书通过Python与Excel的功能对比介绍如何使用Python通过函数式编程完成Excel中的数据处理及分析工作.在Python中pandas库用于数据处理,我 ...
- Vert.x,一个异步、可伸缩、并发应用框架引发的思考
2012年听说过Vert.x这个框架之后,去年大致了解了下,最近开始进一步熟悉这个框架. Vert.x是一个用于下一代异步.可伸缩.并发应用的框架,旨在为JVM提供一个Node.js的替代方案.开发者 ...
- hdu 1171 Big Event in HDU(01背包)
代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; in ...
- Hadoop-2.6.0上的C的API訪问HDFS
在通过Hadoop-2.6.0的C的API訪问HDFS的时候,编译和执行出现了不少问题,花费了几天的时间,上网查了好多的资料,最终还是把问题给攻克了 參考文献:http://m.blog.csdn.n ...
- session timer(一)
功能介绍 SIP并没有为所建立的会话定义存活机制. 虽然用户代理能够通过会话特定的机制推断会话是否超时,可是代理server却做不到这点. 如此一来.代理server有时会无法推断会话是否还是活动的. ...
- jquery06 jQuery.extend 给jQuery函数添加、继承 静态方法
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...
- js --- return返回值 闭包
什么是闭包?这就是闭包! 有权访问另一个函数作用域内变量的函数都是闭包.这里 inc 函数访问了构造函数 a 里面的变量 n,所以形成了一个闭包. function a(){ var n = 0; f ...