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.对于每个节点,求其子树中,哪个距离下的节点数量最多.数量相同时,取较小的那个距离. 题目: 这类题一般的做法是树上的启发式合并,复 ...
随机推荐
- Spark入门:Spark运行架构(Python版)
此文为个人学习笔记如需系统学习请访问http://dblab.xmu.edu.cn/blog/1709-2/ 基本概念 * RDD:是弹性分布式数据集(Resilient Distributed ...
- Helm on K8S
前言 容器的出现,标志着云原生的到来,Docker 基于 Linux 隔离.虚拟化等能力封装了应用:Kubernetes 的出现,建立了云原生时代的技术基础设施,它基于对容器的编排封装了集群:Kube ...
- 编辑器扩展 --- 自动化处理之AssetPostprocessor资源导入
AssetPostprocessor资源导入管线 AssetPostprocessor用于在资源导入时自动做一些设置,比如当导入大量图片时,自动设置图片的类型,大小等.AssetPostprocess ...
- 【C语言】第4章 选择结构程序设计
第4章 选择结构程序设计 C语言有两种选择语句: if 语句,实现两个分支的选择结构 switch 语句,实现多分支的选择结构 输入3个数a,b,c,要求按由小到大的顺序输出. 可以先用伪代码写出算法 ...
- roslaunch保存的log文件没有打印的ERROR信息
最近调试,发现roslaunch启动的节点,log文件中没有ERROR信息. 经过一番查证发现,INFO和WARN是保存在log文件中,ERROR直接打印在terminal 参考: https://g ...
- docker-harbor私有仓库使用笔记
1. 登录harbor管理页面,创建项目,比如yuqx_test 2. admin登录,此处免密登录,正常情况下会输入账号密码 [root@k8s-rancher2 ~]# docker login ...
- JAVA 之 每日一记 之 算法( 给定一个正整数,返回它在 Excel 表中相对应的列名称。 )
题目: 给定一个正整数,返回它在 Excel 表中相对应的列名称. 例如: 1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 -& ...
- vue 引用省市区三级联动(element-ui Cascader)
npm 下载 npm install element-china-area-data -S main.js import {provinceAndCityData,regionData,provinc ...
- 【开发工具】Postman保姆级入门教程
目录 一.简单使用 1. 创建命名空间 2. 创建新集合 3. 按模块整理接口 二.使用环境变量 1. 创建环境与环境变量 2. 使用环境变量 3. 登录后自动更新环境变量 转载请注明出处 一.简单使 ...
- iMX6UL配置MCP2515模块(SPI转CAN)——基于迅为iTOP-iMX6UL开发板
写在前面 在文章"嵌入式Linux的CAN总线配置--基于迅为iTOP-4412开发板"中我给4412开发板配置了SPI转CAN模块,使用的是不带设备树的内核.在本篇文章中,要 ...