牛客练习赛D数学家的谜题线段树+bitset优化
Posted hesorchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛D数学家的谜题线段树+bitset优化相关的知识,希望对你有一定的参考价值。
题目
https://ac.nowcoder.com/acm/contest/11175/D
单点修改和区间查询,询问区间乘能被多少个素数整除。
解题思路
显然是维护区间质因子的数量,可以用带修莫队。
也可以用线段树+bitset优化。将质数映射到1-10000的位中。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, M = 5e4 + 5;
vector<int> fac[N];
bool vis[N];
int rk[N];
void init()
{
int ct = 0;
for (int i = 2; i < N; i++)
{
if (!vis[i])
{
rk[i] = ++ct;
for (int j = i; j < N; j += i)
{
vis[j] = 1;
fac[j].emplace_back(i);
}
}
}
// for (int i = 1; i <= 11; i++)
// cout << i << ' ' << rk[i] << endl;
// cout << ct << endl;
}
int a[M];
struct node
{
int l, r;
bitset<10000> bit;
} tr[M << 2];
void pushup(int k)
{
tr[k].bit = tr[k * 2].bit | tr[k * 2 + 1].bit;
}
void build(int k, int l, int r)
{
tr[k].l = l, tr[k].r = r;
if (l == r)
{
tr[k].bit.reset();
for (auto it : fac[a[l]])
tr[k].bit.set(rk[it]);
return;
}
int mid = l + r >> 1;
build(k * 2, l, mid);
build(k * 2 + 1, mid + 1, r);
pushup(k);
}
void change(int k, int id, int x)
{
if (tr[k].l == tr[k].r)
{
tr[k].bit.reset();
for (auto it : fac[x])
tr[k].bit.set(rk[it]);
return;
}
int mid = tr[k].l + tr[k].r >> 1;
if (id <= mid)
change(k * 2, id, x);
else
change(k * 2 + 1, id, x);
pushup(k);
}
bitset<10000> query(int k, int l, int r)
{
if (tr[k].l == l && tr[k].r == r)
return tr[k].bit;
int mid = tr[k].l + tr[k].r >> 1;
if (r <= mid)
return query(k * 2, l, r);
else if (l > mid)
return query(k * 2 + 1, l, r);
else
return query(k * 2, l, mid) | query(k * 2 + 1, mid + 1, r);
}
void solve()
{
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
build(1, 1, n);
while (m--)
{
int op, l, r;
scanf("%d %d %d", &op, &l, &r);
if (op == 1)
change(1, l, r);
else
cout << query(1, l, r).count() << endl;
}
}
int main()
{
init();
solve();
return 0;
}
以上是关于牛客练习赛D数学家的谜题线段树+bitset优化的主要内容,如果未能解决你的问题,请参考以下文章
浙大哈佛剑桥学者联手破解数学界几十年的谜题,成果登上数学顶刊