bzoj5358: [Lydsy1805月赛]口算训练
分析
首先这是一道很裸的莫队是不是?
开个桶扫一遍,暴力分解质因数可以得到很优秀的
O(Tnn−−√logn)
O
(
T
n
n
l
o
g
n
)
的TLE算法。
其次发现这是一道更裸的主席树。
每个数分解质因数完之后动态开点。
主席树的插入用线段树合并来实现比较优秀。
于是得到了一个
O(Tnlog2n)
O
(
T
n
l
o
g
2
n
)
的优秀算法(PS:第二个log是分解质因数的)
也是学到了用线段树合并来搞主席树的操作。
可以用于一个节点有多个数要插入的情况。
代码
#include<cstdio>
#include<algorithm>
const int N = 1e5 + 10;
int ri() {
char ch = getchar(); int x = 0;
for(;ch < '0' || ch > '9'; ch = getchar()) ;
for(;ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) - '0' + ch;
return x;
}
int pr[N], mn[N], rt[N], tp, tot, sz, ls[N * 120], rs[N * 120], sum[N * 120];
std::pair<int, int>P[33];
void Pre() {
int L = 1e5;
for(int i = 2;i <= L; ++i) {
if(!mn[i]) pr[++tot] = i, mn[i] = tot;
for(int j = 1;j <= tot && i * pr[j] <= L; ++j) {
mn[i * pr[j]] = mn[pr[j]];
if((!i % pr[j])) break;
}
}
}
void Ins(int &p, int L, int R, int ps, int x) {
if(!p) p = ++sz, ls[p] = rs[p] = sum[p] = 0; sum[p] += x;
if(L == R) return ; int m = L + R >> 1;
if(ps <= m) Ins(ls[p], L, m, ps, x);
else Ins(rs[p], m + 1, R, ps, x);
}
int Merge(int u, int v) {
if(!u || !v) return u + v;
sum[u] += sum[v];
ls[u] = Merge(ls[u], ls[v]);
rs[u] = Merge(rs[u], rs[v]);
return u;
}
int Que(int lt, int rt, int L, int R, int ps) {
if(L == R) return sum[rt] - sum[lt];
if(!lt && !rt) return 0;
int m = L + R >> 1;
if(ps <= m) return Que(ls[lt], ls[rt], L, m, ps);
else return Que(rs[lt], rs[rt], m + 1, R, ps);
}
void Div(int a) {
tp = 0;
for(int p = mn[a];a != 1; p = mn[a]) {
int x = 0; for(;!(a % pr[p]); a /= pr[p]) ++x;
P[++tp] = std::make_pair(p, x);
}
}
int main() {
Pre();
for(int T = ri(); T--;) {
int n = ri(), m = ri(); sz = 0;
for(int i = 1;i <= n; ++i) {
rt[i] = 0; int a = ri(); Div(a);
for(int j = 1;j <= tp; ++j) Ins(rt[i], 1, tot, P[j].first, P[j].second);
rt[i] = Merge(rt[i], rt[i - 1]);
}
for(;m--;) {
int l = ri(), r = ri(), d = ri(); Div(d); bool p = true;
for(int i = 1, t;i <= tp; ++i)
if(Que(rt[l - 1], rt[r], 1, tot, P[i].first) < P[i].second) {p = false; break;}
puts(p ? "Yes" : "No");
}
}
return 0;
}