题目
我们发现,如果两个数 x x x 和 y y y 满足 gcd ( x , y ) ≠ 1 \gcd(x,y) \not=1 gcd(x,y)=1,那么这两个数就有同一个属性。
证明:设 gcd ( x , y ) \gcd(x,y) gcd(x,y) 为 k k k,那么如果 k k k 是一个质数,那么 x , y x,y x,y 就有一个为 k k k 的属性,否则,将 k k k 分解质因数,也可以得到一个可以同时被 x , y x,y x,y 整除的质数。
我们看向数据范围: n ≤ 2 ⋅ 1 0 5 n \le 2 \cdot 10^5 n≤2⋅105,但是有一句话给我们指明了方向:
本题测试数据随机,可能是假题。
所以随机数据造出来的树大概率不是这种树:
如果真的有这种退化成链的树,那么出题人可以立马去买一张彩票。
我们算一下这种树出现的概率:如果长度只有 10000 10000 10000,因为这种长度就足够让我们超时了:
首先,每一个节点都有一个固定的父亲,这里,有 10000 10000 10000 个节点都只有一个儿子:
先假设只有 1000 1000 1000 个节点,第一个节点先选一个父亲, 9999 9999 9999 个(排除开自己),然后第二个节点再在剩下的 9998 9998 9998 个节点中再选一个父亲:不重复的概率为 9998 9999 \frac{9998}{9999} 99999998,然后每一个节点都选一个父亲:总的概率为 ! 9999 999 9 10000 \frac{!9999}{9999^{10000}} 999910000!9999,一共有 2 ⋅ 1 0 5 2\cdot 10^5 2⋅105 个节点,在其中选 10000 10000 10000 个,不考虑顺序,再算一下概率: ! 9999 999 9 10000 ⋅ C 200000 10000 \frac{!9999}{9999^{10000}}\cdot C_{200000}^{10000} 999910000!9999⋅C20000010000
估算一下,左边估一下: 10000 × 500 0 2 × 250 0 4 × 125 0 8 ⋯ 1 10000 10000 \times 5000 ^ 2 \times 2500 ^ 4 \times 1250 ^ 8 \cdots 1 ^ {10000} 10000×50002×25004×12508⋯110000,大于等于 1 0 35 10^{35} 1035,右边约为 1 0 20 10^{20} 1020,所以大约为 1 1 0 15 \frac{1}{10^{15}} 10151。
所以暴力就可以了。
往上找,找到满足条件后就可以了,由于大部分可以在 5 5 5 次内找到,超过 log 2 ( n ) \log_2(n) log2(n) 才能找到的概率很小。
AC Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
int n, k;
int a[200100];
int f[200100];
int root;
int op, x, y;
int gcd(int x, int y) {return y == 0 ? x : gcd(y, x % y);}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
f[v] = u;
}
for (int i = 1; i <= n; i++) if (!f[i]) root = i;
while (k--) {
op = 0;
cin >> op >> x;
if (op == 1) {
int st = x;
x = f[x];
while (gcd(a[st], a[x]) == 1) {
if (x == 0) break;
x = f[x];
}
cout << (x == 0 ? -1 : x) << '\n';
}
else {
cin >> y;
a[x] = y;
}
}
return 0;
}