正题

题目链接:https://uoj.ac/problem/33


题目大意

给出\(n\)个点的一棵树

定义\(f(x,y)=gcd(\ dis(x,lca),dis(y,lca)\ )\)。

对于每个\(i\)求有多少对\(f(x,y)=i(x<y)\)

\(1\leq n\leq 10^5\)


解题思路

首先肯定是枚举\(lca\)节点,然后看他子树里的情况,比较麻烦的是\(gcd\)刚刚好是\(d\),但是其实我们可以是\(d\)的倍数的情况,然后后面再容斥出答案。

如果,然后暴力算的话首先需要一个长链剖分,然后每次是\(len\ log\ len\)的。

但是仔细想一想就会发现这个复杂度其实是假的,因为每次暴力算的话的\(len\)是这条链上面那条链的\(len\)。

考虑点其他做法,因为是枚举倍数,我们可以上我们的根号分治

对于\(dis>\sqrt n\)的情况,我们之间暴力枚举倍数,因为这样不会超过\(\sqrt n\)次

对于\(dis\leq \sqrt n\)的情况,我们考虑储存一些东西,设\(g_{i,j}\)表示当前的链中\(dep\)模\(i\)为\(j\)的点的个数,然后处理的时候我们就可以直接用这个来计算了。

这样平衡下来时间复杂度就是\(O(n\sqrt n)\)了


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cctype>
using namespace std;
const int N=2e5+10;
struct node{
int to,next;
}a[N];
int n,T,len[N],dep[N],h[N],g[400][400];
int tot,t[N],ls[N],son[N],*f[N],*now;
long long ans[N],pre[N];
int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;
}
void dfs(int x){
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
dep[y]=dep[x]+1;dfs(y);
if(len[y]>len[son[x]])son[x]=y;
}
len[x]=len[son[x]]+1;
return;
}
void calc(int x,int top){
f[x][0]=1;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==son[x])continue;
f[y]=now;now+=len[y];calc(y,y);
}
if(son[x]){
f[son[x]]=f[x]+1;
calc(son[x],top);
}
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==son[x])continue;
for(int j=1;j<=len[y];j++)t[j]=f[y][j-1];
for(int j=1;j<=len[y];j++)
for(int k=2*j;k<=len[y];k+=j)t[j]+=t[k];
for(int j=1;j<=len[y];j++)
if(j>T){
for(int k=j;k<len[x];k+=j)
ans[j]+=1ll*f[x][k]*t[j];
}
else ans[j]+=1ll*g[j][dep[x]%j]*t[j];
for(int j=1;j<=len[y];j++)
f[x][j]+=f[y][j-1];
for(int j=0;j<len[y];j++)
for(int k=1;k<=T;k++)
g[k][(j+dep[y])%k]+=f[y][j];
}
for(int i=1;i<=T;i++)g[i][dep[x]%i]++;
if(x==top){
for(int i=1;i<=T;i++)
for(int j=0;j<len[x];j++)
g[i][(j+dep[x])%i]=0;
}
return;
}
signed main()
{
n=read();
for(int i=2;i<=n;i++)
addl(read(),i);
dfs(1);T=sqrt(n);
if(T>350)T=350;
f[1]=now=h;now+=len[1];
calc(1,1);
for(int i=n;i>=1;i--)
for(int j=2*i;j<=n;j+=i)
ans[i]-=ans[j];
for(int i=2;i<=n;i++)pre[dep[i]]++;
for(int i=n;i>=1;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. 「WC2010」重建计划(长链剖分/点分治)

    「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...

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

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

  3. Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)

    题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...

  4. BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)

    题意 自己看. 分析 求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做. 先对树长链剖分. ...

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

    [UOJ#33][UR #2]树上GCD(长链剖分,分块) 题面 UOJ 题解 首先不求恰好,改为求\(i\)的倍数的个数,最后容斥一下就可以解决了. 那么我们考虑枚举一个\(LCA\)位置,在其两棵 ...

  6. [UOJ UR #2]树上GCD

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

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

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

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

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

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

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

随机推荐

  1. PHP随手记2--获取随机n位不重复字符

    定义一个函数返回26英文字母中n位不重复随机字符 基本思路是利用内置函数生成随机数,取出该位置字母之后将其删除,再进行下一次随机,最后实现字符串拼接就ok! 代码很简单,通俗易懂,直接上代码吧: 1 ...

  2. 【转】TCP的三次握手与四次挥手理解及面试题

    转自:https://blog.csdn.net/qq_38950316/article/details/81087809 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据 ...

  3. SpringBoot的快速入门

    快速创建一个SpringBoot项目(两种方式:STS版本,IntelliJ IDEA) 1.STS方式:什么是STS?是Spring团队推荐使用的开发工具 所谓的sts就是eclipse升级版 继承 ...

  4. java 捕获组与非捕获组

    非捕获组:格式:(?:xxxx), 如:(?:aaa)\\w+(bbb)\\1,\\1 代表重复捕获的第一组即是(bbb) public static void main(String[] args) ...

  5. 前端下载文档的java工具类

    package com.ry.project.util.commUtil;import freemarker.template.Configuration;import freemarker.temp ...

  6. Servlet过滤器----Filter

    JavaEE的Servlet规范描述了三种技术:Servlet,Filter,Listener (一)过滤器简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过F ...

  7. 前后端数据交互(四)——fetch 请求详解

    fetch 是 XMLHttpRequest 的升级版,使用js脚本发出网络请求,但是与 XMLHttpRequest 不同的是,fetch 方式使用 Promise,相比 XMLHttpReques ...

  8. Mybatis(一)——HelloWorld

    本人的博客一向保持"傻瓜式"的风格. 循序渐进学Mybatis,先konw how,再konw why.先整体,再细节! 本文不讲难懂的概念,先通过一个案例,希望读者跟着本文一步一 ...

  9. C语言中volatile、register、const、static、extern、 auto关键字的作用

    一.volatile详解 volatile的本意是"易变的" 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据.当要求使用volat ...

  10. k8s资源管理(基础操作)

    1. 基础 本文实操基于k8s 1.22.1 # 可以查看资源分配情况 kubectl describe node # 全局资源情况查看 kubectl api-resources 1.1 apply ...