[Codeforces 986E] Prince's Problem

[题目链接]

https://codeforces.com/contest/986/problem/E

[算法]

X到Y的路径积 , 可以转化为X到根的路径积乘Y到根的路径积 , 除以LCA到根的路径积 , 再除以LCA父节点到根的路径积

考虑如何计算根到X路径上每个点与Value的GCD之积

不妨对于每个质数P开一个数组cnt[] , 表示根到当前节点P^i有多少个 , 我们可以在DFS的过程中维护这个数组

将询问离线即可

时间复杂度 : O(V + NlogN + QlogV^2)

[代码]

#include<bits/stdc++.h>
using namespace std;
#define MAXLOG 30
const int P = 1e9 + 7;
const int MAXN = 1e5 + 10;
const int MAXP = 1e6 + 10;
const int MAXV = 1e7 + 10;

struct edge
{
        int to , nxt;
} e[MAXN << 1];
struct info
{
        int value , home;
        bool type;
} ;
int tot , n , t;
int a[MAXN],depth[MAXN],prime[MAXP],head[MAXN],ans[MAXN],f[MAXV];
int cnt[MAXP][MAXLOG],anc[MAXN][MAXLOG];
vector< info > q[MAXN];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - ‘0‘;
    x *= f;
}
inline void addedge(int u,int v)
{
        t++;
        e[t] = (edge){v,head[u]};
        head[u] = t;
}
inline int exp_mod(int a,int n)
{
        int res = 1 , b = a;
        while (n > 0)
        {
                if (n & 1) res = 1ll * res * b % P;
                b = 1ll * b * b % P;
                n >>= 1;
        }
        return res;
}
inline int inv(int x) { return exp_mod(x,P - 2); }
inline void dfs(int u,int fa)
{
        depth[u] = depth[fa] + 1;
        for (int i = 1; i < MAXLOG; i++)
        {
                if (depth[u] <= (1 << i)) break;
                anc[u][i] = anc[anc[u][i - 1]][i - 1];
        }
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to;
                if (v == fa) continue;
                anc[v][0] = u;
                depth[v] = depth[u] + 1;
                dfs(v,u);
        }
}
inline int lca(int u,int v)
{
      if (depth[u] > depth[v]) swap(u,v);
        for (int i = MAXLOG - 1; i >= 0; i--)
        {
                if (depth[anc[v][i]] >= depth[u])
                        v = anc[v][i];
        }
        if (u == v) return u;
        for (int i = MAXLOG - 1; i >= 0; i--)
        {
                if (anc[u][i] != anc[v][i])
                        u = anc[u][i] , v = anc[v][i];
        }
        return anc[u][0];
}
inline void modify(int x,int delta)
{
        for (int i = 1; 1ll * prime[i] * prime[i] <= x; i++)
        {
                if (x % prime[i] == 0)
                {
                        int p = 0;
                        while (x % prime[i] == 0)
                        {
                                x /= prime[i];
                                p++;
                        }
                        cnt[i][p] += delta;
                }
        }
        if (x != 1)
        {
                int pos = lower_bound(prime + 1,prime + tot + 1,x) - prime;
                cnt[pos][1] += delta;
        }
}
inline int query(int x)
{
        int ret = 1;
        for (int i = 1; 1ll * prime[i] * prime[i] <= x; i++)
        {
                if (x % prime[i] == 0)
                {
                        int p = 0;
                        while (x % prime[i] == 0)
                        {
                                p++;
                                x /= prime[i];
                        }
                        int s = 0;
                        for (int j = 1; j <= p; j++) s += cnt[i][j] * j;
                        for (int j = p + 1; j < MAXLOG; j++) s += cnt[i][j] * p;
                        ret = 1ll * ret * exp_mod(prime[i],s) % P;
                }
         }
         if (x != 1)
         {
                int pos = lower_bound(prime + 1,prime + tot + 1,x) - prime;
                int s = 0;
                for (int i = 1; i < MAXLOG; i++) s += cnt[pos][i];
                ret = 1ll * ret * exp_mod(x,s) % P;
        }
        return ret;
}

inline void solve(int u,int fa)
{
        modify(a[u],1);
        for (unsigned i = 0; i < q[u].size(); i++)
        {
                if (q[u][i].type)    ans[q[u][i].home] = 1ll * ans[q[u][i].home] * query(q[u][i].value) % P;
                else ans[q[u][i].home] = 1ll * ans[q[u][i].home] * inv(query(q[u][i].value)) % P;
        }
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to;
                if (v == fa) continue;
                solve(v,u);
        }
        modify(a[u],-1);
}

int main()
{

        read(n);
        for (int i = 2; i < MAXV; i++)
        {
                if (!f[i])
                {
                        f[i] = i;
                        prime[++tot] = i;
                }
                for (int j = 1; j <= tot; j++)
                {
                        int tmp = i * prime[j];
                        if (tmp >= MAXV) break;
                        f[tmp] = prime[j];
                        if (prime[j] == f[i]) break;
                }
        }
        for (int i = 1; i < n; i++)
        {
                int u , v;
                read(u); read(v);
                addedge(u,v);
                addedge(v,u);
        }
        dfs(1,0);
        for (int i = 1; i <= n; i++) read(a[i]);
        int Q;
        read(Q);
        for (int i = 1; i <= Q; i++)
        {
                int u , v , x;
                read(u); read(v); read(x);
                int Lca = lca(u,v);
                q[u].push_back((info){x,i,true});
                q[v].push_back((info){x,i,true});
                q[Lca].push_back((info){x,i,false});
                if (Lca != 1) q[anc[Lca][0]].push_back((info){x,i,false});
                ans[i] = 1;
        }
        solve(1,0);
        for (int i = 1; i <= Q; i++) printf("%d\n",ans[i]);

        return 0;

}

[Codeforces 986E] Prince's Problem

原文地址:https://www.cnblogs.com/evenbao/p/9739488.html

时间: 2024-08-01 10:09:28

[Codeforces 986E] Prince's Problem的相关文章

http://codeforces.com/contest/575/problem/B

题目链接: http://codeforces.com/contest/575/problem/B 题解: 代码: #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 1e5 + 10; const int DEG = 22; const in

Codeforces 442B Andrey and Problem(贪心)

题目链接:Codeforces 442B Andrey and Problem 题目大意:Andrey有一个问题,想要朋友们为自己出一道题,现在他有n个朋友,每个朋友想出题目的概率为pi,但是他可以同时向多个人寻求帮助,不过他只能要一道题,也就是如果他向两个人寻求帮助,如果两个人都成功出题,也是不可以的. 解题思路:贪心,从概率最大的人开始考虑,如果询问他使得概率变大,则要询问. #include <cstdio> #include <cstring> #include <a

http://codeforces.com/contest/741/problem/B B. Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses

题意: 给出上限体重W 然后还给出每个人的体重wi 和 魅力值 bi 互为伙伴的对(xi, yi) 可以凑成group 思路: 并查集找出所有的group 暴力背包 对于每一个group 要选出这一组内选一个人时的最优结果, 如果所有人的体重和小于等于W,还得考虑选所有人的情况 #include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include &l

CodeForces 776D The Door Problem【并查集】

CodeForces 776D The Door Problem[并查集]并查集 设 f 1--m 表示 开的情况 m+1--2*m 表示关的情况 对于每盏灯 如果他 是关的 则 x--y x+m--y+m 表示要同关 或者同开 如果他 是开的 则 x+m--y x--y+m 表示一个关 一个开如果一盏灯 的 x 连向 了 x+m 则表示是矛盾了 那么久是错误的 题意:给你n个门,和m组开关,每扇门都有两个开关控制,每个开关控制x扇门,如果选择了某组开关,则使这组开关里的每个开关控制的所有的门按

Codeforces 30D King&#39;s Problem? 模拟

首先将n个点排序,找出排序后的K,然后分情况讨论. 当 k == n+1时,显然是 k->1->n || k->n->1这两种的较小值,因为三角形的两边之和大于第三边. 当1 <= k && k <= n 时: 1 , k -> 1 -> n+1 -> k+1 ->n  ||  k -> n -> n+1 -> k-1 -> 1,当k+1 || k-1 不存在时将对应步骤忽略. 2 , k - > 1

[CF986E]Prince&#39;s Problem

题意:给一棵带点权$w_i$的树,多次询问$(u,v,x)$,求出$\prod\limits_{i\in\text{path}(u,v)}(w_i,x)$ 因为是乘法,所以可以把路径询问拆成到根询问,这样就可以离线做了 因为求$\gcd$的本质是质因数指数取$\min$,所以在离线dfs时每到一个点就把它的点权质因数分解打上标记然后统计答案即可 具体地,对于$w_x=\prod\limits_{i=1}^kp_i^{a_i}$,我们把每个$p_i$的$1\cdots a_i$次幂乘上$p_i$的

Codeforces 1019C Sergey&#39;s problem 其他

原文链接https://www.cnblogs.com/zhouzhendong/p/CF1019C.html 题目传送门 - CF1019C 题意 给定一个有 $n$ 个节点 . $m$ 条边的有向图,没有自环,但是可能存在环. 现在要求选出一个点集满足一下条件. 设原来的所有点构成的点集为 $V$ ,选出的点集为 $S$,则: 1. 对于所有满足 $x,y\in S$ 的点 $x,y$ ,有向边 $(x,y)$ 不存在. 2. 对于所有满足 $x\in S,y\in V$ 的点,点 $x$

Frets On Fire --- 2019 Codeforces Global Round 2 Problem D

原题:https://codeforces.com/contest/1119/problem/D 题意大概是一个n行1e18列的矩阵,其中每行第一个数为s[i],剩下的数每行依次以1的速度递增.就是说,矩阵元素 a[i][j] = s[i] + j .有q个询问,每个询问有两个参数l,r,求矩阵第l列到第r列(所有行)一共出现了几个不同的数. 这道题首先要先想到,两个参数 [l,r] 其实等价于一个参数 [0,r-l] ,也就是说矩阵第0~r-l行出现的数字的个数其实和第l-r行出现的个数是一样

CodeForces 633B A Trivial Problem

传送门:http://codeforces.com/problemset/problem/633/B 题意:给你一个常数m,要你找出几个数,这几个数的阶乘的最后m位 都是0. 显然 末尾有0 一定能除以10 10可以换成5*2的形式, 那么我们就可以找5的倍数,(如果有5出现 也一定有2) ———————————————————————————————————— 渣渣之见,随便转载. #include<cstdio> int main() { long long n,k=0; // 看i阶乘的