CF986E Prince's Problem 题解

*2800,不是很难,但有点卡常。

考虑 gcd\gcd 不是很好直接算,经典套路是分解质因数。

ww 分解质因数,设结果为 w=p1a1×p2a2××pkakw=p_1^{a_1} \times p_2^{a_2} \times \cdots \times p_k^{a_k}

枚举每一个 ww 的质因数 piaip_i^{a_i},对于路径上每一个点 uu,假设这个点权也有相同质因数 pibip_i^{b_i},那么对答案的贡献为 min{ai,bi}\min\{a_i,b_i\}

由于 ai,bi23(223=8388608<107,224>107)a_i,b_i \leq 23(2^{23}=8388608<10^7,2^{24}>10^7),所以我们不妨枚举这个 min{ai,bi}\min\{a_i,b_i\},设为 xx,然后问题转化为路径上有几个点有 pixp_i^x 这个质因数。本质就是数颜色。

容易树上差分将询问变为一个点到根数颜色,离线之后一次 DFS 动态维护前缀和数组并统计答案即可。然而这个做法复杂度比较大,大概是 O(qlog3V+(n+q)V)O(q \log^3 V+(n+q) \sqrt V) 的,不过不太能跑满,但还是需要卡一卡。

#pragma GCC optimize("-Ofast,fast-math,-inline")
#pragma GCC target("avx,sse,sse2,sse3,popcnt")
#pragma pack(1)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;

const int N = 1e5 + 5, MOD = 1e9 + 7;

vector<pair<int, int> > v[N];
int n, a[N], q;
vector<int> G[N];

struct Query
{
	int u, v, w;
	Query(int _u, int _v, int _w) : u(_u), v(_v), w(_w) {}
	Query() = default;
}p[N];

int nfa[N][21], dep[N];

void dfs(int u, int f)
{
	nfa[u][0] = f;
	dep[u] = dep[f] + 1;
	for (auto& j : G[u])
	{
		if (j ^ f) dfs(j, u);
	}
}

vector<pair<int, int> > qre[N];
int ans[N];
int rid[N * 8];

int sum[N * 8][25];

long long qpow(long long a, long long b)
{
	long long res = 1, base = a;
	while (b)
	{
		if (b & 1LL) res = res * base % MOD;
		base = base * base % MOD;
		b >>= 1LL;
	}
	return res;
}

int xx[N * 55], kkk[N * 55];

struct Nqe
{
	int sgn, id;

	Nqe() = default;

	Nqe(int sgn, int id)
		: sgn(sgn), id(id)
	{
	}
};

vector<Nqe> each[N];

int LCA(int u, int v)
{
	if (u == v) return u;
	if (dep[u] < dep[v]) swap(u, v);
	int k = dep[u] - dep[v], c = 0;
	while (k)
	{
		if (k & 1) u = nfa[u][c];
		k >>= 1;
		c++;
	}
	if (u == v) return u;
	for (int i = 20; i >= 0; i--)
	{
		if (nfa[u][i] != nfa[v][i]) u = nfa[u][i], v = nfa[v][i];
	}
	return nfa[u][0];
}
int res[N * 55];
int idx;

void redfs(int u, int f)
{
	for (auto& j : v[u])
	{
		sum[j.first][j.second]++;
	}
	for (auto& j : each[u])
	{
		res[j.id] += j.sgn * sum[xx[j.id]][kkk[j.id]];
	}
	for (auto& j : G[u])
	{
		if (j ^ f) redfs(j, u);
	}
	for (auto& j : v[u])
	{
		sum[j.first][j.second]--;
	}
}

int L[N], R[N];
int k2[N * 55];

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n;
	vector<int> divs;
	int pu = 0;
	for (int i = 1; i < n; i++)
	{
		int u, v;
		cin >> u >> v;
		if (!pu) pu = u;
		G[u].emplace_back(v);
		G[v].emplace_back(u);
	}
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		int ra = a[i];
		for (int j = 2; 1LL * j * j <= ra; j++)
		{
			if (ra % j == 0)
			{
				int c = 0;
				while (ra % j == 0) ra /= j, c++;
				v[i].emplace_back(make_pair(j, c));
			}
		}
		if (ra != 1) v[i].emplace_back(make_pair(ra, 1));
		sort(v[i].begin(), v[i].end());
		for (auto& j : v[i]) divs.emplace_back(j.first);
	}
	dfs(1, 0);
	for (int i = 1; i <= 20; i++)
	{
		for (int j = 1; j <= n; j++) nfa[j][i] = nfa[nfa[j][i - 1]][i - 1];
	}
	cin >> q;
	for (int i = 1; i <= q; i++)
	{
		ans[i] = 1;
		int u, v, w;
		cin >> u >> v >> w;
		p[i] = Query(u, v, w);
		int ra = w;
		for (int j = 2; 1LL * j * j <= ra; j++)
		{
			if (ra % j == 0)
			{
				int c = 0;
				while (ra % j == 0) ra /= j, c++;
				qre[i].emplace_back(make_pair(j, c));
			}
		}
		if (ra != 1) qre[i].emplace_back(make_pair(ra, 1));
		sort(qre[i].begin(), qre[i].end());
		for (auto& j : qre[i]) divs.emplace_back(j.first);
	}
	sort(divs.begin(), divs.end());
	divs.erase(unique(divs.begin(), divs.end()), divs.end());
	for (auto& j : divs)
	{
		int rj = j;
		int nj = lower_bound(divs.begin(), divs.end(), j) - divs.begin() + 1;
		rid[nj] = rj;
	}
	for (int i = 1; i <= n; i++)
	{
		for (auto& j : v[i]) j.first = lower_bound(divs.begin(), divs.end(), j.first) - divs.begin() + 1;
	}
	for (int i = 1; i <= q; i++)
	{
		for (auto& j : qre[i]) j.first = lower_bound(divs.begin(), divs.end(), j.first) - divs.begin() + 1;
	}
	for (int i = 1; i <= q; i++)
	{
		int u = p[i].u, vv = p[i].v;
		int l = LCA(u, vv);
		L[i] = idx + 1;
		for (auto& j : qre[i])
		{
			long long nowres = 1LL;
			for (int k = 0; k <= 23; k++)
			{
				if (nowres > (long long)1e7) break;
				nowres *= rid[j.first];
				idx++;
				xx[idx] = j.first, kkk[idx] = k;
				each[u].emplace_back(Nqe(1, idx));
				each[vv].emplace_back(Nqe(1, idx));
				each[l].emplace_back(Nqe(-2, idx));
				k2[idx] = min(k, j.second);
				for (auto& g : v[l])
				{
					if (g == make_pair(j.first, k))
					{
						ans[i] = 1LL * ans[i] * qpow(rid[j.first], min(j.second, k)) % MOD;
					}
				}
			}
		}
		R[i] = idx; // 1
	}
	redfs(1, 0);
	for (int i = 1; i <= q; i++)
	{
		for (int j = L[i]; j <= R[i]; j++)
		{
			ans[i] = (1LL * ans[i] * qpow(qpow(rid[xx[j]], k2[j]), res[j])) % MOD;
		}
		cout << ans[i] << "\n";
	}
	return 0;
}
posted @   HappyBobb  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示