CodeForces - 986E Prince's Problem

Description

给一棵树,每个点有点权 \(a_i\) ,每次给 \(u,v,x\) ,求 \(u\)\(v\) 路径上每个点的点权与 \(x\)\(gcd\) 的积。

\(n,m\le 10^5,1\le a_i\le 10^7\)

Solution

离线,答案相当与四条从根出发的链拼起来,分解质因数。

#include<bits/stdc++.h>
using namespace std;

template <class T> void read(T &x) {
    x = 0; bool flag = 0; char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar()) flag |= ch == '-';
    for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48; flag ? x = ~x + 1 : 0;
}

//#pragma GCC diagnostic error "-std=c++14"

#define N 100010
#define rep(i, a, b) for (auto i = (a); i <= (b); ++i)
#define drp(i, a, b) for (auto i = (a); i >= (b); --i)
#define P 1000000007

bool notPri[10000010];
int pri[664580 + 10], priCnt;

void init(int n) {
    int m = sqrt(n + 0.5);
    rep(i, 2, m) if (!notPri[i]) for (int j = i * i; j <= n; j += i) notPri[j] = 1;
    rep(i, 2, n) if (!notPri[i]) pri[++priCnt] = i;
}

vector<int> g[N];

int fa[N][18], dep[N];
void dfs(int u) {
    rep(i, 1, 17) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for (int v : g[u]) if (v ^ fa[u][0]) fa[v][0] = u, dep[v] = dep[u] + 1, dfs(v);
}

int getLca(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    drp(i, 17, 0) if (dep[fa[u][i]] >= dep[v]) u = fa[u][i]; if (u == v) return u;
    drp(i, 17, 0) if (fa[u][i] ^ fa[v][i]) u = fa[u][i], v = fa[v][i]; return fa[u][0];
}

struct Data {
    int x, id;
    bool type;
    Data(int x = 0, int id = 0, bool type = 0) : x(x), id(id), type(type) {}
};

vector<Data> q[N];

int qpow(int x, int k) {
    int ret = 1;
    for (; k; k >>= 1, x = 1ll * x * x % P) if (k & 1) ret = 1ll * ret * x % P;
    return ret;
}

int a[N], ans[N], cnt[664580 + 10][25];

void update(int val, int del) {
    for (int i = 1; 1ll * pri[i] * pri[i] <= val; ++i) if (val % pri[i] == 0) {
        int p = 0;
        for (; val % pri[i] == 0; val /= pri[i], ++p);
        cnt[i][p] += del;
    }
    if (val != 1) cnt[lower_bound(pri + 1, pri + 1 + priCnt, val) - pri][1] += del;
}

int query(int val) {
    int ret = 1;
    for (int i = 1; 1ll * pri[i] * pri[i] <= val; ++i) if (val % pri[i] == 0) {
        int p = 0, t = 0;
        for (; val % pri[i] == 0; val /= pri[i], ++p);
        rep(j, 1, p) t += cnt[i][j] * j;
        rep(j, p + 1, 24) t += cnt[i][j] * p;
        ret = 1ll * ret * qpow(pri[i], t) % P;
    }
    if (val == 1) return ret;
    int pos = lower_bound(pri + 1, pri + 1 + priCnt, val) - pri;
    int t = 0;
    rep(i, 1, 24) t += cnt[pos][i];
    return 1ll * ret * qpow(val, t) % P;
}

void solve(int u) {
    update(a[u], 1);
    for (auto t : q[u]) {
        if (t.type) ans[t.id] = 1ll * ans[t.id] * query(t.x) % P;
        else ans[t.id] = 1ll * ans[t.id] * qpow(query(t.x), P - 2) % P;
    }
    for (int v : g[u]) if (v != fa[u][0]) solve(v);
    update(a[u], -1);
}

#define pb push_back

int main() {
    init(10000000);
    int n, m; read(n);
    rep(i, 2, n) {
        int u, v; read(u), read(v);
        g[u].pb(v), g[v].pb(u);
    }
    dep[1] = 1; dfs(1);
    rep(i, 1, n) read(a[i]);
    read(m);
    rep(i, 1, m) {
        int u, v, x; read(u), read(v), read(x);
        int lca = getLca(u, v);
        ans[i] = 1;
        q[u].pb(Data(x, i, 1)), q[v].pb(Data(x, i, 1)), q[lca].pb(Data(x, i, 0));
        if (lca != 1) q[fa[lca][0]].pb(Data(x, i, 0));
    }
    solve(1);
    rep(i, 1, m) printf("%d\n", ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/aziint/p/9752455.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值