bzoj5358: \[Lydsy1805月赛\]口算训练 主席树

bzoj5358: [Lydsy1805月赛]口算训练

分析

首先这是一道很裸的莫队是不是?
开个桶扫一遍,暴力分解质因数可以得到很优秀的 O ( T n n l o g n ) 的TLE算法。
其次发现这是一道更裸的主席树。
每个数分解质因数完之后动态开点。
主席树的插入用线段树合并来实现比较优秀。
于是得到了一个 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;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/80524132
今日推荐