这道题是有根树点分治+烧脑的容斥+神奇的分块

因为是规定1为根,还要求LCA,所以我们不能像在无根树上那样随便浪了,必须规定父亲,并作特殊讨论

因为gcd并不好求,所以我们用容斥转化一下,求x为gcd的因数的个数,这样就可以随便统计了,个人觉得代码比题解要好懂。

又因为统计完重心的所有子树,还有重心的父亲,所以在这个分治块内沿着重心的父亲一路向上爬,这时候重心的子树到重心的父亲的距离是变的,所以我们用神奇的分块大法,分类讨论,$≤\sqrt{n}$使用数组记录答案,方便以后再用到的时候统计,$>\sqrt{n}$时直接暴力统计,因为此时统计的复杂度并不高。这样使时间复杂度空降为$O(n\sqrt{n})$。个人感觉题解说得太含糊了,一切都不如直接看代码明晰,或者说题解是帮助看懂代码的233

这道题细节太多了,跪了1天半终于AC了蛤蛤蛤蛤蛤蛤蛤

这道题我先膜了鏼爷的代码,因为各种指针看不懂啊,但学习了非递归求重心的新姿势,无限仰膜Orz!!!SDOI就是要练就各种非递归能力

然后我又膜了ShallWe的题解,学会了容斥统计的方法,无限仰膜啊!!!巧妙的特判和两个指针的移动使得容斥统计不重不漏,真是太神奇了!!!

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 200003;
void read(int &k) {
k = 0; int fh = 1; char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if (c == '-') fh = -1;
for(; c >= '0' && c <= '9'; c = getchar())
k = (k << 1) + (k << 3) + c - '0';
k = k * fh;
} bool vis[N];
struct node {
int nxt, to;
} E[N];
int qu[N], ct[N], n, m, fa[N], de, deep[N], cnt = 0, point[N], root, sz[N], boo[N];
ll t[503][503], cn[N], sct[N], scn[N], ans2[N], S[N]; void ins(int x, int y) {E[++cnt].nxt = point[x]; E[cnt].to = y; point[x] = cnt;}
void findrt(int x) {
int p = 0, q = 0; qu[++q] = x;
while (p != q) {
int u = qu[++p];
boo[u] = sz[u] = 1;
for(int tmp = point[u]; tmp; tmp = E[tmp].nxt)
if (!vis[E[tmp].to])
qu[++q] = E[tmp].to;
}
for(int i = q; i; --i) {
if (boo[qu[i]] && sz[qu[i]] * 2 >= q) {root = qu[i]; return;}
sz[fa[qu[i]]] += sz[qu[i]];
if (sz[qu[i]] * 2 >= q)
boo[fa[qu[i]]] = 0;
}
}//非递归找重心!!!国家队rank3的鏼爷Orz给SDOIers带来福利 void BFS(int x) {
deep[x] = 1;
int p = 0, q = 0; qu[++q] = x;
while (p != q) {
int u = qu[++p]; ++ct[deep[u]];
for(int tmp = point[u]; tmp; tmp = E[tmp].nxt)
if (!vis[E[tmp].to])
deep[E[tmp].to] = deep[u] + 1, qu[++q] = E[tmp].to;
}
de = deep[qu[q]];
} void Q(int x) {
vis[x] = 1;
int up = 0, upp = 0;
for(int tmp = point[x]; tmp; tmp = E[tmp].nxt)
if (!vis[E[tmp].to]) {
BFS(E[tmp].to);
up = max(up, de);
for(int i = 1; i <= de; ++i)
for(int j = i; j <= de; j += i)
cn[i] += ct[j];
for(int i = 1; i <= de; ++i) {
ans2[i] += ct[i];
sct[i] += ct[i];
S[i] += scn[i] * cn[i];
scn[i] += cn[i];
ct[i] = cn[i] = 0;
}
} sct[0] = 1;
int step = 0, son = x, line, to;
for(int i = fa[x]; !vis[i] && i; son = i, i = fa[i]) {
++step; to = 0;
for(int tmp = point[i]; tmp; tmp = E[tmp].nxt)
if (!vis[E[tmp].to] && E[tmp].to != son)
BFS(E[tmp].to), to = max(to, de);
de = to;
upp = max(upp, de);
for(int j = 1; j <= de; ++j)
for(int k = j; k <= de; k += j)
cn[j] += ct[k];
line = min(de, m);
for(int j = 1; j <= line; ++j) {
to = step % j;
if (t[j][to] == -1) {
t[j][to] = 0;
for(int k = (j - to) % j; k <= up; k += j)
t[j][to] += sct[k];
}
S[j] += t[j][to] * cn[j];
}
for(int j = m + 1; j <= de; ++j)
for(int k = (j - step % j) % j; k <= up; k += j)
S[j] += sct[k] * cn[j];
for(int j = 1; j <= de; ++j)
ct[j] = cn[j] = 0;
++ans2[step];
} //下面是向ShallWe学的
int L = 1, R = 0, tot = step + up;
ll now = 0;
for(int i = 2; i <= tot; ++i) {
if (R + 1 < i) now += sct[++R];
if (L + step < i) now -= sct[L++];
ans2[i] += now;
}
//仰膜上方ShallWe的代码 line = min(m, upp);
for(int i = 1; i <= line; ++i)
for(int j = 0; j < i; ++j)
t[i][j] = -1;
for(int i = 0; i <= up; ++i)
sct[i] = scn[i] = 0; if (son != x) {
findrt(son);
Q(root);
}
for(int tmp = point[x]; tmp; tmp = E[tmp].nxt)
if (!vis[E[tmp].to]) {
findrt(E[tmp].to);
Q(root);
}
} ll ans[N];
int main() {
read(n); m = (sqrt(n));
for(int i = 2; i <= n; ++i) {
read(fa[i]);
ins(fa[i], i);
} memset(t, -1, sizeof(t));
findrt(1);
Q(root);
for(int i = n - 1; i; --i)
for(int j = i + i; j < n; j += i)
S[i] -= S[j];
for(int i = 1; i < n; ++i)
printf("%lld\n", S[i] + ans2[i]); return 0;
}

_(:з」∠)_

【UR #2】树上GCD的更多相关文章

  1. UOJ33 [UR #2] 树上GCD 【点分治】【容斥原理】【分块】

    题目分析: 树上点对问题首先想到点分治.假设我们进行了点分治并递归地解决了子问题.现在我们合并问题. 我们需要找到所有经过当前重心$ c $的子树路径.第一种情况是LCA为当前重心$ c $.考虑以$ ...

  2. [UOJ UR #2]树上GCD

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

  3. 【uoj33】 UR #2—树上GCD

    http://uoj.ac/problem/33 (题目链接) 题意 给出一棵${n}$个节点的有根树,${f_{u,v}=gcd(dis(u,lca(u,v)),dis(v,lca(u,v)))}$ ...

  4. 【UOJ#33】【UR#2】树上GCD 有根树点分治 + 容斥原理 + 分块

    #33. [UR #2]树上GCD 有一棵$n$个结点的有根树$T$.结点编号为$1…n$,其中根结点为$1$. 树上每条边的长度为$1$.我们用$d(x,y)$表示结点$x,y$在树上的距离,$LC ...

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

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

  6. [UOJ]#33. 【UR #2】树上GCD

    题目大意:给定一棵有根树,边长均为1,对于每一个i,求树上有多少个点对,他们到lca距离的gcd是i.(n<=200,000) 做法:先容斥,求出gcd是i的倍数的点对,考虑长链剖分后从小到大合 ...

  7. UOJ#33. 【UR #2】树上GCD 点分治 莫比乌斯反演

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ33.html 题解 首先我们把问题转化成处理一个数组 ans ,其中 ans[i] 表示 d(u,a) 和 ...

  8. uoj33 【UR #2】树上GCD

    题目 大致是长剖+\(\rm dsu\ on\ tree\)的思想 先做一个转化,改为对于\(i\in[1,n-1]\)求出有多少个\(f(u,v)\)满足\(i|f(u,v)\),这样我们最后再做一 ...

  9. Codeforces 842C Ilya And The Tree 树上gcd

    题目链接 题意 给定一棵根为\(1\)的树.定义每个点的美丽值为根节点到它的路径上所有点的\(gcd\)值.但是对于每个点,在计算它的美丽值时,可以将这条路径上某个点的值变为\(0\)来最大化它的美丽 ...

随机推荐

  1. 什么是 A 轮融资?有 B轮 C轮么?

    融资的顺序是A轮 B轮 C轮这之前还有天使轮,种子轮,首轮在这之后还有vc/pe,ipo等等,只是一些不同时段的融资 Chen Shu 知乎用户.千叶光.angle LI 等人赞同 就是公司的初卖.再 ...

  2. [No000015]坏习惯一大堆?别怕,还有救-坏习惯一堆,怎么好好学习嘛!

  3. android系统架构解析

    以上是我在这个课题下的一些参考博客或者网页链接.里面有对于android架构的一些较好的分析理解,接下来是楼主在阅读后自己的一些整理. Android采用层次化系统架构,官方公布的标准架构如下图所示. ...

  4. 32位计时器极端情况下产生的bug

    用每毫秒更新的32位变量用来计时, 使用这个变量计算离上次操作是否间隔10秒.两种写法: f - lastF <10, 和 f

  5. JS给文本框赋值后,在页面后台取不到文本框值的解决方法

    转自:http://www.cnblogs.com/qiaohd/archive/2012/03/23/2413660.html (ReadOnly.disabled 都有可能造成取值取不到) 开发一 ...

  6. Django admin 显示图片

    我有一个表用来储存轮播图片,有一个 `picture` 字段储存的是图片的url,图片的 url 通过上传文件到 cdn 获得.目前这个表的编辑是通过自定义一个 `ModelForm`,然后重写 Dj ...

  7. caffe的python接口学习(2):生成solver文件

    caffe在训练的时候,需要一些参数设置,我们一般将这些参数设置在一个叫solver.prototxt的文件里面,如下: base_lr: 0.001 display: 782 gamma: 0.1 ...

  8. Intel pin 2.14/CentOS 6 X86-64/安装

    环境:Intel Pin 2.14 CentOS 6 X86-64 --linux.tar.gz 进入 ./source/tools/ManualExamples make all TARGET=in ...

  9. Theano2.1.7-基础知识之设置的配置和编译模式

    来自:http://deeplearning.net/software/theano/tutorial/modes.html Configuration Settings and Compiling ...

  10. opencv6.5-imgproc图像处理模块之轮廓

    接opencv6.4-imgproc图像处理模块之直方图与模板 这部分的<opencv_tutorial>上都是直接上代码,没有原理部分的解释的. 十一.轮廓 1.图像中找轮廓 /// 转 ...