嘘~ 正在从服务器偷取页面 . . .

洛谷P2441 角色属性树 题解


洛谷P2441 角色属性树 题解

题目链接:P2441 角色属性树

题意

绪萌同人社是一个有趣的组织,该组织结构是一个树形结构。有一个社长,直接下属一些副社长。每个副社长又直接下属一些部长……。

每个成员都有一个萌点的属性,萌点属性是由一些质数的萌元素乘积构成(例如,猫耳的值是 \(2\),弱气的值是 \(3\),黄毛的值是 \(5\),病娇的值是 \(7\),双马尾的值是 \(11\) 等等)

举个例子,正妹是双份的猫耳,而且有一份弱气,她的属性值为 \(2\times 2\times 3=12\)

现在组员关心一个问题,希望知道离自己最近且有相同萌元素上司是谁,例如,属性值为 \(2、4、6、45\) 这样的属性值都算是和正妹有相同的属性。

然而,组员可能会随时变化自己的属性。啊。。感觉好麻烦啊。。

输入格式

第一行,\(n,k\) 表示成员数与询问的次数

第二行,\(n\) 个数,分别是 \(1\)\(n\) 号成员的属性值

接下来 \(n-1\) 行,\(x_i,y_i\) 表示 \(x_i\)\(y_i\) 的上司。

接下来来 \(k\) 行,有两种情况

\(1\ u_i\):询问离 \(u_i\) 成员最近且有相同萌元素上司。

\(2\ u_i\)\(a\) 更改 \(u_i\) 的属性值为 \(a\)

输出格式

对于每个 \(1\) 类型的询问,输出符合要求的编号。如果没有符合要求的编号,输出 \(-1\)

数据范围

本题测试数据随机,可能是假题。

对于 \(100\%\) 的数据,\(n\le 200000\)\(k<100000\),修改次数 \(\le 50,a_i\le 2^{31}-1\)

前置知识:欧拉乘积公式 \[ \zeta(z)=\prod_{p \in \mathbb{P}} \frac{1}{1-p^{-z}} \] 考虑两个自然数 \(a,b\) 互质的概率。

如果 \(a,b\) 互质,则 \(a,b\) 没有公约数 \(2,3,5,\cdots\) ,即 \[ \left(1 - \frac{1}{2}\times \frac{1}{2}\right)\times \left(1 - \frac{1}{3}\times \frac{1}{3}\right) \times \left(1- \frac{1}{5}\times \frac{1}{5}\right)\times \cdots \] 整理一下可得 \[ \prod_{p \in \mathbb{P}}(1-p^{-2}) = \frac{1}{\zeta(2)} \]众所周知 \(\zeta(2)=\frac{\pi^2}{6}\) ,概率即为 \(\frac{6}{\pi^2}\approx0.6079271\)

于是两个自然数不互质的概率为 \(p = 1 - \frac{6}{\pi^2} \approx 0.392\)

对于本题,暴力 \(k\) 次询问得到答案的概率为 \(f(k)=\sum_{0 \le i < k}(1-p)^ip\)

计算可知在 \(k = 10\)\(f(k)\approx0.993105\) ,这已经是非常高的概率了。

因为数据是随机的,所以暴力的复杂度为 \(\mathcal{O}(q\log n)\) ,这里的 \(\log n\) 是树高

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e5 + 15))

int n,q,a[N],fa[N];
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
int dfs(int x, int y)
{
    if(x == 0) return -1;
    if(gcd(a[x], a[y]) > 1) return x;
    return dfs(fa[x], y);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> q;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1, x, y; i < n; i++) { cin >> x >> y; fa[y] = x; }
    for(int i = 1, x, y; i <= q; i++)
    {
        cin >> x;
        if(x == 1) {
            cin >> y; cout << dfs(fa[y], y) << '\n';
        }else { cin >> x >> y; a[x] = y; }
    }
    return 0;
}

题外话

因为没有概率这个标签,所以假装这道题是随机化(总不能说是玄学吧)。


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录