题目大意:

就是给你一棵以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/长链剖分)的更多相关文章

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

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

  2. Codeforces 1009 F. Dominant Indices(长链剖分/树上启发式合并)

    F. Dominant Indices 题意: 给一颗无向树,根为1.对于每个节点,求其子树中,哪个距离下的节点数量最多.数量相同时,取较小的那个距离. 题目: 这类题一般的做法是树上的启发式合并,复 ...

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

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

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

    题目链接 \(O(n^2)\)的\(DP\)很容易想,\(f[u][i]\)表示在\(u\)的子树中距离\(u\)为\(i\)的点的个数,则\(f[u][i]=\sum f[v][i-1]\) 长链剖 ...

  5. 【CF1009F】Dominant Indices(长链剖分优化DP)

    点此看题面 大致题意: 设\(d(x,y)\)表示\(x\)子树内到\(x\)距离为\(y\)的点的个数,对于每个\(x\),求满足\(d(x,y)\)最大的最小的\(y\). 暴力\(DP\) 首先 ...

  6. CF1009F Dominant Indices 长链剖分

    题目传送门 https://codeforces.com/contest/1009/problem/F 题解 长链剖分的板子吧. 令 \(dp[x][i]\) 表示 \(x\) 的子树中的深度为 \( ...

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

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

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

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

  9. 2019.01.08 codeforces 1009F. Dominant Indices(长链剖分)

    传送门 长链剖分模板题. 题意:给出一棵树,设fi,jf_{i,j}fi,j​表示iii的子树中距离点iii距离为jjj的点的个数,现在对于每个点iii要求出使得fif_ifi​取得最大值的那个jjj ...

随机推荐

  1. Go 语言编程

    [课程名称]Go 语言编程   [课程时间]2014年7月30日(周三) 20:50 - 22:00         [课程安排]20:50-21:00     通过邮件地址登录网络课堂       ...

  2. vim插件之marks

    最近在看源码的过程中,发现一点很不方便的地方,就是当我在几个相关的类来回跳转的时候,之前定位的关键代码很容易找不到,结果进程需要重复查找关键点.虽然当时想到了可以通过marks来标志,但是,因为mar ...

  3. spring 中国下载点

    http://repo.spring.io/libs-release-local/org/springframework/spring/ spring 中国下载点

  4. [USACO07JAN]平衡的阵容Balanced Lineup RMQ模板题

    Code: #include<cstdio> #include<algorithm> using namespace std; const int maxn = 50000 + ...

  5. Hexo 相册实践

    灵感 想给自已的blog添加一个相册功能.给生活中的点点滴滴留影记录.搜寻网络上给Next主题添加相册功能的基本上没有,只能重头到尾开始一点点的实践.    大致的想法:  1. 相册展示类似于归档一 ...

  6. PXE无人值守部署centos7.4操作系统

    1.基础环境: 镜像ISO文件名为:CentOS-7-x86_64-DVD-1804.iso 2.安装需要的软件包 yum install dhcp xinetd syslinux httpd tft ...

  7. linux下,yum 安装mysql

    顺手记录一下安装mysqlclient 先安装mysql-devel yum install mysql-devel 再安装mysqlclient pip3 install mysqlclient 开 ...

  8. libc.so.6: version GLIBC_2.14 not found

    https://blog.csdn.net/heylun/article/details/78833050

  9. pip-window安装

    windows 安装: 保证计算机联网直接使用cmd 执行 python -m pip install -U pip 自动安装 找到 python安装的路径 C:\Users\Administrato ...

  10. Ubuntu 16.04安装mysql (连接)

    1.安装mysql sudo apt-get install mysql-server 注:若出现依赖问题安装失败,先执行以下命令sudo apt-get install -f 2.安装过程中会输入密 ...