UOJ#33-[UR #2]树上GCD【长链剖分,根号分治】
正题
题目链接: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【长链剖分,根号分治】的更多相关文章
- 「WC2010」重建计划(长链剖分/点分治)
「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...
- CF1009F Dominant Indices(树上DSU/长链剖分)
题目大意: 就是给你一棵以1为根的树,询问每一个节点的子树内节点数最多的深度(相对于这个子树根而言)若有多解,输出最小的. 解题思路: 这道题用树链剖分,两种思路: 1.树上DSU 首先想一下最暴力的 ...
- Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)
题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...
- BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)
题意 自己看. 分析 求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做. 先对树长链剖分. ...
- 【UOJ#33】【UR #2】树上GCD(长链剖分,分块)
[UOJ#33][UR #2]树上GCD(长链剖分,分块) 题面 UOJ 题解 首先不求恰好,改为求\(i\)的倍数的个数,最后容斥一下就可以解决了. 那么我们考虑枚举一个\(LCA\)位置,在其两棵 ...
- [UOJ UR #2]树上GCD
来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 看完题目,一般人都能想到 容斥稳了 .这样我们只要统计有多少点对满足gcd是i的倍数. 考虑长链剖分,每次合并的时候,假设我已经求出轻 ...
- hdu 4607 Park Visit(树上最长链)
求树上最长链:两遍搜索. 第一次从树上任意点开始,最远点必然是某一条最长链上的端点u. 第二次从u开始,最远点即该最长链的另一端点. 先在最长链上走,不足再去走支链. 把询问数m错打成n,狠狠wa了一 ...
- [HDU4607]Park Visit(树上最长链)
HDU#4607. Park Visit 题目描述 Claire and her little friend, ykwd, are travelling in Shevchenko's Park! T ...
- Codeforces 1009 F. Dominant Indices(长链剖分/树上启发式合并)
F. Dominant Indices 题意: 给一颗无向树,根为1.对于每个节点,求其子树中,哪个距离下的节点数量最多.数量相同时,取较小的那个距离. 题目: 这类题一般的做法是树上的启发式合并,复 ...
随机推荐
- PHP随手记2--获取随机n位不重复字符
定义一个函数返回26英文字母中n位不重复随机字符 基本思路是利用内置函数生成随机数,取出该位置字母之后将其删除,再进行下一次随机,最后实现字符串拼接就ok! 代码很简单,通俗易懂,直接上代码吧: 1 ...
- 【转】TCP的三次握手与四次挥手理解及面试题
转自:https://blog.csdn.net/qq_38950316/article/details/81087809 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据 ...
- SpringBoot的快速入门
快速创建一个SpringBoot项目(两种方式:STS版本,IntelliJ IDEA) 1.STS方式:什么是STS?是Spring团队推荐使用的开发工具 所谓的sts就是eclipse升级版 继承 ...
- java 捕获组与非捕获组
非捕获组:格式:(?:xxxx), 如:(?:aaa)\\w+(bbb)\\1,\\1 代表重复捕获的第一组即是(bbb) public static void main(String[] args) ...
- 前端下载文档的java工具类
package com.ry.project.util.commUtil;import freemarker.template.Configuration;import freemarker.temp ...
- Servlet过滤器----Filter
JavaEE的Servlet规范描述了三种技术:Servlet,Filter,Listener (一)过滤器简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过F ...
- 前后端数据交互(四)——fetch 请求详解
fetch 是 XMLHttpRequest 的升级版,使用js脚本发出网络请求,但是与 XMLHttpRequest 不同的是,fetch 方式使用 Promise,相比 XMLHttpReques ...
- Mybatis(一)——HelloWorld
本人的博客一向保持"傻瓜式"的风格. 循序渐进学Mybatis,先konw how,再konw why.先整体,再细节! 本文不讲难懂的概念,先通过一个案例,希望读者跟着本文一步一 ...
- C语言中volatile、register、const、static、extern、 auto关键字的作用
一.volatile详解 volatile的本意是"易变的" 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据.当要求使用volat ...
- k8s资源管理(基础操作)
1. 基础 本文实操基于k8s 1.22.1 # 可以查看资源分配情况 kubectl describe node # 全局资源情况查看 kubectl api-resources 1.1 apply ...