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 ...
随机推荐
- Invalid command 'WSGIScriptAlias', perhaps misspelled or defined by a module not included in the ser
没有Include wsgi,执行: sudo a2enmod wsgi 可能出现以下的错误 ERROR: Module mod-wsgi does not exist! 安装 libapache2- ...
- POJ 1167 The Buses 暴搜+剪枝
思路: 先把能选的路线都预处理出来 按照能停的车的多少排个序 (剪枝1) 搜搜搜 如果当前剩的车÷当前能停车的多少+deep>=ans剪掉 (剪枝2) //By SiriusRen #inclu ...
- 洛谷P1586 四方定理
题目描述 四方定理是众所周知的:任意一个正整数nn ,可以分解为不超过四个整数的平方和.例如:25=1^{2}+2^{2}+2^{2}+4^{2}25=12+22+22+42 ,当然还有其他的分解方案 ...
- 如何把本地的项目推送到github上面去
前题:本地已经建好了项目,但电脑上没有安装git (windows 系统) 1.首页从网上下载git 并安装. 2.进入项目所在的文件夹,右键鼠标 3.新建.gitignore文件 touch .g ...
- LINUX中,find结合grep正则表达式,快速查找代码文件。
###目的###LINUX中,find结合grep正则表达式快速查找代码. 例如经常有需求:查找当前目录下所有.h文件中,"public开头,中间任意字符,以VideoFrameReceiv ...
- W3C高级算法挑战之python实现
最近在学python,网上很难找到对应的算法题网站,专业算法网站大部分都是国外的,之前在w3cschool看到有三个级别的Javascript脚本算法挑战,尝试用python实现,代码量相对比较少,如 ...
- 【Codeforces Round #425 (Div. 2) B】Petya and Exam
[Link]:http://codeforces.com/contest/832/problem/B [Description] *能代替一个字符串(由坏字母组成); ?能代替单个字符(由好字母组成) ...
- CSUOJ 1638 Continued Fraction
1638: Continued Fraction Time Limit: 1 Sec Memory Limit: 128 MB Description Input Output Sample Inp ...
- vim 基础学习之global
global命令可以在指定模式下,匹配行上进行Ex命令 使用格式: :[range]g[lobal]/{pattern}/[cmd] range-是执行范围(如果缺省,是%) global-命令关键字 ...
- Linux下MySQL允许远程连接以及授权命令
--针对某个库做授权 GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'%' IDENTIFIED BY 'mypassword' WITH GRANT OPTION; ...