【UOJ#33】【UR #2】树上GCD(长链剖分,分块)

题面

UOJ

题解

首先不求恰好,改为求\(i\)的倍数的个数,最后容斥一下就可以解决了。

那么我们考虑枚举一个\(LCA\)位置,在其两棵不同的子树中选择两个点,那么贡献就是这两段的\(gcd\)。

那么发现要统计的东西类似于\(u\)的子树中,深度为\(d\)的点的个数,这个可以很容易的用长链剖分来维护,那么维护出这个数组之后就可以\(O(\log {dep})\)的对于贡献进行计算。然而这个复杂度是假的,因为你每次都需要一次\(O(\log dep)\),这个\(dep\)不能是长链的\(dep\),而这里却是长链长度,所以这样子复杂度不正确,

那么考虑别的方法,那就分块。

对于\(dis\ge \sqrt n\)的情况,因为其倍数的个数只有\(\sqrt n\)个,所以直接暴力统计,这部分全局的总复杂度是\(O(n\sqrt n)\)。

对于\(dis\lt \sqrt n\),维护\(g[i][j]\)表示当前重链的所有子树中,深度模\(i\)为\(j\)的点的个数,这个东西可以在因为\(dis\lt \sqrt n\),所以每次\(O(\sqrt n)\)的加入就行了,这样子全局复杂度也是\(O(n\sqrt n)\)。

这样子复杂度就做到了\(O(n\sqrt n)\)。

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAX 200200
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next;}e[MAX];int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,hson[MAX],md[MAX],dep[MAX];
void dfs1(int u,int ff)
{
md[u]=dep[u]=dep[ff]+1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
dfs1(v,u);
if(md[v]>md[hson[u]])hson[u]=v;
}
if(hson[u])md[u]=md[hson[u]];
}
int tmp[MAX<<2],*f[MAX],*id=tmp,t[MAX],g[355][355],BLK=350;
ll ans[MAX],pre[MAX];
void dfs(int u,int ff,int fl)
{
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff||v==hson[u])continue;
f[v]=id;id+=md[v]-dep[v]+1;dfs(v,u,0);
}
if(hson[u])f[hson[u]]=f[u]+1,dfs(hson[u],u,1);
f[u][0]=1;int mx=md[u]-dep[u];
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff||v==hson[u])continue;
int s=md[v]-dep[v]+1;
for(int j=1;j<=s;++j)t[j]=f[v][j-1];
for(int j=1;j<=s;++j)
for(int k=j+j;k<=s;k+=j)
t[j]+=t[k];
for(int j=1;j<=s;++j)
if(j>BLK)for(int k=j;k<=mx;k+=j)ans[j]+=1ll*f[u][k]*t[j];
else ans[j]+=1ll*g[j][dep[u]%j]*t[j];
for(int j=0;j<s;++j)f[u][j+1]+=f[v][j];
for(int j=dep[v];j<=md[v];++j)
for(int k=1;k<=BLK;++k)
g[k][j%k]+=f[v][j-dep[v]];
}
for(int i=1;i<=BLK;++i)++g[i][dep[u]%i];
if(!fl)
for(int k=1;k<=BLK;++k)
for(int j=dep[u];j<=md[u];++j)
g[k][j%k]=0;
}
int main()
{
n=read();
for(int i=2,x;i<=n;++i)x=read(),Add(x,i);
dfs1(1,0);f[1]=id;id+=md[1]+1;dfs(1,0,0);
for(int i=n;i;--i)
for(int j=i+i;j<=n;j+=i)
ans[i]-=ans[j];
for(int i=2;i<=n;++i)pre[dep[i]-1]+=1;
for(int i=n;i;--i)pre[i]+=pre[i+1];
for(int i=1;i<n;++i)printf("%lld\n",ans[i]+pre[i]);
return 0;
}

【UOJ#33】【UR #2】树上GCD(长链剖分,分块)的更多相关文章

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

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

  2. UOJ#33-[UR #2]树上GCD【长链剖分,根号分治】

    正题 题目链接:https://uoj.ac/problem/33 题目大意 给出\(n\)个点的一棵树 定义\(f(x,y)=gcd(\ dis(x,lca),dis(y,lca)\ )\). 对于 ...

  3. [UOJ UR #2]树上GCD

    来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 看完题目,一般人都能想到 容斥稳了 .这样我们只要统计有多少点对满足gcd是i的倍数. 考虑长链剖分,每次合并的时候,假设我已经求出轻 ...

  4. hdu 4607 Park Visit(树上最长链)

    求树上最长链:两遍搜索. 第一次从树上任意点开始,最远点必然是某一条最长链上的端点u. 第二次从u开始,最远点即该最长链的另一端点. 先在最长链上走,不足再去走支链. 把询问数m错打成n,狠狠wa了一 ...

  5. [HDU4607]Park Visit(树上最长链)

    HDU#4607. Park Visit 题目描述 Claire and her little friend, ykwd, are travelling in Shevchenko's Park! T ...

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

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

  7. LOJ3053 十二省联考2019 希望 容斥、树形DP、长链剖分

    传送门 官方题解其实讲的挺清楚了,就是锅有点多-- 一些有启发性的部分分 L=N 一个经典(反正我是不会)的容斥:最后的答案=对于每个点能够以它作为集合点的方案数-对于每条边能够以其两个端点作为集合点 ...

  8. 【BZOJ3653】谈笑风生(长链剖分)

    [BZOJ3653]谈笑风生(长链剖分) 题面 BZOJ 洛谷 权限题啊.... 题解 首先根据题目给的条件,发现\(a,b\)都要是\(c\)的父亲. 所以这三个点是树上的一条深度单增的链. 因为\ ...

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

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

随机推荐

  1. 解决 bash: vue command not found

    背景  : win10 使用  yarn  全局 安装  vue/cli 后   yarn  global add  @vue/cli 提示安装成功 使用vue create   提示  bash: ...

  2. 「白帽挖洞技能提升」ThinkPHP5 远程代码执行漏洞-动态分析

    ThinkPHP是为了简化企业级应用开发和敏捷WEB应用开发而诞生的,在保持出色的性能和至简代码的同时,也注重易用性.但是简洁易操作也会出现漏洞,之前ThinkPHP官方修复了一个严重的远程代码执行漏 ...

  3. NoSuchMethodError 常见原因及解决方法

    相 关 阅 读 导读 『StabilityGuide』是阿里多位阿里技术工程师共同发起的稳定性领域的知识库开源项目,涵盖性能压测.故障演练.JVM.应用容器.服务框架.流量调度.监控.诊断等多个技术领 ...

  4. python 自带模块 os模块

    os模块 首先可以打开cmd输入python进入交互界面  然后输入 dir(os) 就可以看到os的全部用法了  我们简单的举几个例子就行了. 写入os.getcwd()  可以查看当前所在路径 i ...

  5. Python元组与字符串操作(9)——随机数、元组、命名元组

    随机数 import random #导入random模块 randint(a,b) 返回[a,b]之间的整数 random.randint(0,9) randrange([start],stop,[ ...

  6. Axel多线程工具安装

    Axel 是 Linux 下一个不错的轻量级高速下载工具,支持HTTP/FTP/HTTPS/FTPS协议,支持多线程下载.断点续传,且可以从多个地址或者从一个地址的多个连接来下载同一个文件. 大家使用 ...

  7. Qt 之 qwt 和 qwtpolar 的编译配置

    1  Qwt Qwt 全称为 Qt Widgets for Technical Applications,用于专业技术领域的可视化显示,如下所示: 左图为二阶系统的频率响应:中图为德国小城 Fried ...

  8. JS高阶---语句分号相关

    [总结] 小括号和中括号开头的在其前必须加封号: [主体] 首先搜索下 [主体] (1)讨论---编码风格问题 (2)什么情况必须用封号? 1.其后跟着匿名式函数调用 此时可以在匿名函数前加:如下所示 ...

  9. 201871010109-胡欢欢《面向对象程序设计(java)》第6-7周学习总结

    实验六 继承定义与使用 实验时间 2019-9-29 第一部分:理论部分. 1.继承:已有类来构建新类的一种机制.档定义了一个新类继承另一个类时,这个新类就继承了这个类的方法和域,同时在新类中添加新的 ...

  10. 【入门篇一】SpringBoot简介(1)

    官网:https://spring.io/projects/spring-boot 一.什么是SpringBoot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新S ...