U623471
我又在从事这种 wyy 事业了。
subtask1
显然暴力,有多种不同的暴力方式供你选择。
subtask2
考虑预处理出每个数的质因数,然后暴力就可以,复杂度是 \(O(n^2 \log V)\) 的。
subtask3
发现 \(a_i\) 全是质数就将题目转化为了求链上众数。这一操作可以用树上莫队 \(+\) 值域分块来做,复杂度达到 \(O(n \sqrt n)\)。回滚莫队应该不行。
或者也可以考虑用树上莫队 \(+\) zkw 线段树 \(+\) 线段树顶层分块(自己造的词,真不知道怎么称呼)来做,令剩余的线段树森林的高度为 \(h\),复杂度到达了 \(O(nh \sqrt n + \frac {n^2}{2^h})\),可能也行。
subtask4
\(a_i \le 1000\),这已经可以直接暴力分解每一个质因数然后直接树上前缀和来做了。复杂度是 \(O(n\frac { V} {\ln V})\)
subtask5
发现 \((10^3)^2 = 10^6\),如果你的 sub3,sub4 都过了,那么很容易想到根号分治。一个数只有一个大于 \(\sqrt V\) 的质因数,把这个质因数单独拿出来,然后就把问题分成了维护大于 \(10^3\) 的质数和小于 \(10^3\) 的数两部分,这显然分别是 sub3 和 sub4。这已经几乎是正解了,复杂度 \(O(q\sqrt n + n\frac {\sqrt V} {\ln \sqrt V})\)。
subtask6
\(\pi(\sqrt {10^9})\) 很大,发现瓶颈在于空间,根号分治也无法让树上前缀和求出小质数的部分开下,考虑将边界划分到 \(\sqrt[3]{V}\),莫队维护大于这个值的两个质因数就可以完成了。复杂度 \(O(q\sqrt n + n\frac {\sqrt V} {\ln \sqrt V})\),已经可以通过。
然后你发现时间瓶颈来自于拆质因数(并不),然后可以学习 Pollard-Rho 拆最后两个质数,可以做到 \(O(q\sqrt n + n( {\frac {\sqrt[3] V} {\ln \sqrt [3] V} + \sqrt [6]V} \frac {\log V^ {\frac 23}}{63}))\) 的复杂度,单论拆质因数可以让某个极限点的预处理快一倍,至于其他的数据……并不极限。
好像还有一个加速除法的科技叫什么 ExactDivision 的,那个应该也可以把拆质因数加速得很快,然而我不会。
神秘附加题:
-
发现可以用树上莫队直接做 \(O(n\sqrt n \log V)\) 左右的东西,deepseek 写了没过,也许有卡常大佬?
-
deepseek 给出了一种很怪又有点道理的东西,发现有 \(\frac {\sqrt V}{\ln \sqrt V} = 1200\) 个质数开不下所以干脆分批处理?也许可行?
超大常数 std:
// code by 樓影沫瞬_Hz17
#include <bits/stdc++.h>
using namespace std;
#define getc() getchar_unlocked()
#define putc(a) putchar_unlocked(a)
#define en_ putc('\n')
#define e_ putc(' ')
using pii = pair<int, int>;
template<class T1, class T2> T1 max(T1 a, T2 b) { return a > b ? a : a = b;}
template<class T1, class T2> T1 min(T1 a, T2 b) { return a < b ? a : a = b;}
constexpr int N = 2e5 + 10, B = 1200, D = 550, T = N / D + 100;
int n, Q;
int sum[180][N];
int fa[N], sz[N], wc[N], top[N], dep[N];
vector<int> e[N];
inline void dfs(int u, int f) {
fa[u] = f, dep[u] = dep[f] + 1, sz[u] = 1;
for(int v : e[u])
if(v != f) {
dfs(v, u);
sz[u] += sz[v];
wc[u] = sz[wc[u]] > sz[v] ? wc[u] : v;
}
}
bool vis[1010];
int pri[190], cnp;
inline void line() {
for(int i = 2; i <= 1000; i ++) {
if(!vis[i]) pri[++ cnp] = i;
for(int j = 1; pri[j] * i <= 1000 and j <= cnp; j ++) {
vis[i * pri[j]] = 1;
if(i % pri[j] == 0) break;
}
}
}
inline int qp(int i, int k, const int mod) {
int res = 1;
for(; k; k >>= 1, i = 1ll * i * i % mod)
if(k & 1) res = 1ll * res * i % mod;
return res;
}
constexpr int ltpri[5] = {2, 3, 5, 23};
inline bool MR(int p) {
if(p < 2) return false;
int t, k, c = 0;
for(t = p - 1, k = 0; !(t & 1); k ++, t >>= 1);
for(int i : ltpri) {
if(p == i) return true;
int a = qp(i, t, p);
if(a == 1) {c ++; continue;}
for(int i = 0; i < k; i ++) {
if(a == p - 1) {c ++; break;}
a = (long long)a * a % p;
}
}
return c == 4;
}
mt19937 rd(20070831);
inline int PR(int x) {
if(x == 4) return 2;
int s, t, c, tp, gl, val;
uniform_int_distribution<int> u0(1, x - 1);
s = t = tp = gl = 0, val = 1, c = u0(rd);
for(gl = 1; ; gl <<= 1, s = t, val = 1) {
for(tp = 1; tp <= gl; tp ++) {
t = ((long long)t * t % x + c);
val = (long long)val * abs(t - s) % x;
if((tp % 40) == 0) {
int d = __gcd(val, x);
if(d > 1) return d;
}
}
int d = __gcd(val, x);
if(d > 1) return d;
}
}
inline pair<vector<int>, vector<int> > divide(int x) {
vector<int> res1, res2;
for(int i = 1; i <= cnp; i ++) {
if(x == 1) break;
if(x % pri[i] == 0) {
while(x % pri[i] == 0) {
res1.emplace_back(i);
x /= pri[i];
}
}
}
if(x != 1) {
if(MR(x)) res2.emplace_back(x);
else {
int d = PR(x);
while(d == x) d = PR(x);
res2.emplace_back(d);
res2.emplace_back(x / d);
}
}
return {res1, res2};
}
int rr[N], st[N], ed[N], cntn, cnto;
inline void dfs2(int u, int tp) {
top[u] = tp;
st[u] = ++ cnto, rr[cnto] = u;
if(wc[u]) dfs2(wc[u], tp);
for(int v : e[u])
if(v != fa[u] and v != wc[u]) dfs2(v, v);
ed[u] = ++ cnto, rr[cnto] = u;
}
inline int lca(int u, int v) {
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] > dep[v] ? v : u;
}
inline pii query(int u, int v, int l) {
int res = 0, id;
for(int i = 1; i <= 172; i ++) {
int t = sum[i][u] + sum[i][v] - sum[i][l] - sum[i][fa[l]];
if(t >= res) res = t, id = i;
}
return {pri[id], res};
}
inline void dfs3(int u) {
for(int i = 1; i <= 172; i ++) sum[i][u] += sum[i][fa[u]];
for(int v : e[u])
if(v != fa[u]) dfs3(v);
}
struct QUE {
int l, r, lca, id;
} q[N];
int cnt[N], cntcnt[T][N / 2], mxmx[T], pos[N], bel[N], L[T], R[T];
vector<int> num[N];
int a[N], flg[N];
pii ans[N];
inline void red(int i) {
for(int v : num[i]) {
cntcnt[bel[v]][cnt[v]] --;
mxmx[bel[v]] -= (mxmx[bel[v]] == cnt[v] and !cntcnt[bel[v]][cnt[v]]);
cntcnt[bel[v]][-- cnt[v]] ++;
}
}
inline void add(int i) {
for(int v : num[i]) {
cntcnt[bel[v]][cnt[v] ++] --;
cntcnt[bel[v]][cnt[v]] ++;
mxmx[bel[v]] = mxmx[bel[v]] > cnt[v] ? mxmx[bel[v]] : cnt[v];
}
}
vector<int> Hash;
inline pii query() {
int mx = 0, id;
for(int i = 1; L[i]; i ++)
if(mx <= mxmx[i]) mx = mxmx[i], id = i;
for(int i = R[id]; i >= L[id]; i --)
if(cnt[i] == mx) return {Hash[i - 1], mx};
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("subtask6_1.in", "r", stdin);
freopen("2.out", "w", stdout);
#endif
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
line();
cin >> n >> Q;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1, u, v; i < n; i ++) {
cin >> u >> v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
dfs(1, 0);
dfs2(1, 1);
for(int i = 1; i <= n; i ++) {
auto v = divide(a[i]);
num[i] = v.second;
for(int w : v.first) sum[w][i] ++;
}
dfs3(1);
for(int i = 1; i <= n; i ++)
for(int v : num[i]) Hash.emplace_back(v);
sort(Hash.begin(), Hash.end());
Hash.erase(unique(Hash.begin(), Hash.end()), Hash.end());
for(int i = 1; i <= n; i ++)
for(int&v : num[i]) v = lower_bound(Hash.begin(), Hash.end(), v) - Hash.begin() + 1;
for(int i = 1; R[i - 1] != Hash.size(); i ++) {
L[i] = (i - 1) * D + 1, R[i] = min(i * D, Hash.size());
for(int j = L[i]; j <= R[i]; j ++) bel[j] = i;
}
for(int i = 1, u, v; i <= Q; i ++) {
cin >> u >> v;
if(st[u] > st[v]) swap(u, v);
int l = lca(u, v);
ans[i] = query(u, v, l);
if(l == u) q[i] = {st[u], st[v], 0, i};
else q[i] = {ed[u], st[v], l, i};
}
for(int i = 1; i <= cnto; i ++) pos[i] = (i - 1) / B + 1;
sort(q + 1, q + 1 + Q, [](const QUE&a, const QUE&b) {
return pos[a.l] == pos[b.l] ? pos[a.l] & 1 ? a.r < b.r : a.r > b.r : pos[a.l] < pos[b.l];
});
for(int l = 1, r = 0, i = 1; i <= Q; i ++) {
while(l < q[i].l) {
flg[rr[l]] --;
if(flg[rr[l]] == 1) add(rr[l]);
if(flg[rr[l]] == 0) red(rr[l]);
l ++;
}
while(l > q[i].l) {
l --;
flg[rr[l]] ++;
if(flg[rr[l]] == 1) add(rr[l]);
if(flg[rr[l]] == 2) red(rr[l]);
}
while(r < q[i].r) {
r ++;
flg[rr[r]] ++;
if(flg[rr[r]] == 1) add(rr[r]);
if(flg[rr[r]] == 2) red(rr[r]);
}
while(r > q[i].r) {
flg[rr[r]] --;
if(flg[rr[r]] == 1) add(rr[r]);
if(flg[rr[r]] == 0) red(rr[r]);
r --;
}
if(q[i].lca) add(q[i].lca);
pii t = query();
if(t.second >= ans[q[i].id].second) ans[q[i].id] = t;
if(q[i].lca) red(q[i].lca);
}
for(int i = 1; i <= Q; i ++)
cout << ans[i].first << ' ' << ans[i].second << '\n';
}
// 星間~ 干渉~ 融解~ 輪迴~ 邂逅~ 再生~ ララバイ~

浙公网安备 33010602011771号