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

因为是规定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. 单机搭建Android开发环境(四)

    单机搭建安卓开发环境,前三篇主要是磨刀霍霍,这一篇将重点介绍JDK.REPO.GIT及编译工具的安装,下载项目代码并编译.特别说明,以下操作基于64位12.04 Server版Ubuntu.若采用其他 ...

  2. AC日记——将字符串中的小写字母换成大写字母 openjudge 1.7 13

    13:将字符串中的小写字母转换成大写字母 总时间限制:  1000ms 内存限制:  65536kB 描述 给定一个字符串,将其中所有的小写字母转换成大写字母. 输入 输入一行,包含一个字符串(长度不 ...

  3. java函数参数默认值

    java函数参数默认值 今天,需要设定java函数参数的默认值,发现按照其它语言中的方法行不通 java中似乎只能通过函数的重载来实现 函数参数默认代码

  4. java 25 - 2 网络编程之 网络通信三要素

    网络通信三要素 IP地址: InetAddress 网络中设备的标识,不易记忆,可用主机名(计算机的标识号) 端口号: 用于标识进程的逻辑地址,不同进程的标识(正在运行的软件的标识号) 传输协议: 通 ...

  5. 4种sql分页

    四种方式实现SQLServer 分页查询 SQLServer 的数据分页: 假设现在有这样的一张表:CREATE TABLE test( id int primary key not null ide ...

  6. CSS3之文本阴影text-shadow

  7. HTML 学习笔记 CSS样式(边框)

    元素的边框(border)是围绕元素内容和内边距的一条或多条线 CSS border 属性允许你规定边框的样式 宽度和颜色 CSS 边框 在 HTML 中,我们使用表格来创建文本周围的边框,但是通过使 ...

  8. iOS UIControl 详解

    UIControl是UIView的子类,当然也是UIResponder的子类.UIControl是诸如UIButton,UISwitch,UItextField等控件的父类,它本身包含了一些属性和方法 ...

  9. 10 Things Every Java Programmer Should Know about String

    String in Java is very special class and most frequently used class as well. There are lot many thin ...

  10. 51nod lyk与gcd

    1678 lyk与gcd 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将  ai  ...