先说部分分
30分暴力合并儿子的信息求解就好了
40分的话可以考虑对于先求出\(\gcd (d(u,a),d(v,a))\)为\(d\)的倍数,然后容斥一发
然后先说一种启发式合并的做法吧(个人认为这个做法比较好写
需要求出\(\gcd (d(u,a),d(v,a))\)为\(d\)的倍数
记\(f[n][d]\)为\(n\)这个点子树距离\(n\)为\(kd\)的有多少个
对\(d\)与\(\sqrt n\)大小关系分类讨论
当\(d \leq \sqrt n\)时
\(\mathcal O(n)\)做一遍拓扑序\(dp\)
此部分复杂度\(\mathcal O(n \sqrt n)\)
当\(d > \sqrt n\)时
启发式合并次数不会超过\(\sqrt n\)
由于统计答案的时候状态数不会很多
暴力隔\(d\)跳就好了
复杂度经过处理后得到一个上界\(nk \ln {\dfrac{\sqrt n}{k}}\),\(k\)是块大小
当\(k = \sqrt n\)时复杂度是小于\(\mathcal O(n \sqrt n)\)的
可以参考一下http://vfleaking.blog.uoj.ac/blog/38中lyx的证明
总复杂度为\(\mathcal O(n \sqrt n)\)
还有一种基于分治的做法
同样需要求出\(\gcd (d(u,a),d(v,a))\)为\(d\)的倍数
考虑当前的分治重心为\(t\)
会对所有经过他的点对\((u, v)\)会产生贡献
当\((u, v)\)是\(t\)子树内的点的时候
用\(\mathcal O(n \log n)\)暴力统计即可
当\((u, v)\)只有一点在\(t\)子树内
枚举\(t\)到当前分治的根\(root\)上的节点\(a_i\)
求出所有\(a_i\)子树的点但是非\(t\)子树的点到\(a_i\)距离
然后枚举\(d\)
同样对\(d\)与\(\sqrt n\)大小关系分类讨论
对于\(t\)子树中\(d\le \sqrt n\)预处理
当\(d > \sqrt n\)时暴力求解
一层分治复杂度是\(\mathcal O(n \sqrt n)\)的
总的复杂度也是\(\mathcal O(n \sqrt n)\)
学习了一发主定理
对于\(T(n) = aT(\dfrac{n}{b}) + f(n)\)
设\(g(n) = n ^{log_b^a}\)
\(f<g\)时\(T=g\)
\(f=g\)时\(T=g \log n\)
\(f > g\)时且对\(\forall c < 1\)且足够大的\(n\)
有\(af(\dfrac{n}{b}) \le cf(n)\) \(T = f\)
#include <bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
x = 0; char c = getchar(); bool f = 0;
for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if(f) x = -x;
}
const int N = 2e5 + 233;
int n;
int fa[N], pred[N], nowd[N], dep[N], has[N], f[N];
int ans[N], tmp[N];
inline void uni(vector<int> &a, vector<int> &b) {
int sa = (int) a.size(), sb = (int) b.size();
for(int i = 1; i <= sb; i ++)
a[sa - i] += b[sb - i];
b.clear();
}
main(void) {
read(n);
dep[1] = 0;
for(int i = 2; i <= n; i ++) {
read(fa[i]); nowd[i] = i;
dep[i] = dep[fa[i]] + 1;
tmp[1] ++; tmp[dep[i] + 1] --;
}
fo(i, n) tmp[i] += tmp[i - 1];
int K = min((int) sqrt(n), 167ll);
int maxdep = *max_element(dep + 1, dep + n + 1);
// calculate for d \leq \sqrt n
fo(d, K) {
fo(i, n) has[i] = f[i] = 0;
fo(i, n) {
pred[i] = nowd[i];
nowd[i] = fa[nowd[i]];
}
for(int i = n; i > 1; i --) {
f[i] ++;
has[pred[i]] += f[i];
if(has[i] && fa[i]) {
ans[d] += has[i] * f[fa[i]];
f[fa[i]] += has[i];
}
}
}
// calculate for d > \sqrt n
vector<int> f[N];
for(int i = n; i >= 2; i --) {
f[i].push_back(1);
if((int) f[i].size() > (int) f[fa[i]].size())
swap(f[i], f[fa[i]]);
int in = (int) f[i].size();
int fan = (int) f[fa[i]].size();
if(in > K && fan > K) {
int up = min(maxdep, min(in, fan));
for(int d = K + 1; d <= up; d ++) {
int cnti = 0, cntfa = 0;
for(int k = d; k <= in; k += d)
cnti += f[i][in - k];
for(int k = d; k <= fan; k += d)
cntfa += f[fa[i]][fan - k];
ans[d] += 1ll * cnti * cntfa;
}
}
uni(f[fa[i]], f[i]);
}
for(int i = n; i >= 1; i --)
for(int j = i + i; j <= n; j += i)
ans[i] -= ans[j];
for(int i = 1; i <= n - 1; i ++)
cout << ans[i] + tmp[i] << "\n";
}