嘘~ 正在从服务器偷取页面 . . .

SP19568 PRMQUER - Prime queries 题解


SP19568 PRMQUER - Prime queries 题解

题目链接:SP19568 PRMQUER - Prime queries

题意

这是一个简单的题目

给定 \(N\) 个数,你需要对它们依次进行 \(Q\) 次操作。每次操作的格式如下。

  1. 三个整数 \(A\) \(V\) \(l\) 表示给第 \(l\) 个数加上 \(V\)

  2. 四个整数 \(R\) \(a\) \(l\) \(r\) 表示把区间 \([l,r]\) 的数都变为 \(a\)

  3. 三个整数 \(Q\) \(l\) \(r\) 表示询问区间 \([l,r]\) 里,小于等于 \(10^7\) 的素数有多少个。

数据保证任何时刻这 \(N\) 个数都不会有一个数大于 \(10^9\)

输入格式

第一行两个整数 \(N\)\(Q\) 分别表示数的个数和操作的个数,第二行有 \(N\) 个整数,表示这些数的初始大小。之后 \(Q\) 行每行一次操作,输入格式如题目描述所述。

输出格式

对于每个操作 \(3\) 输出一行整数表示这个操作的答案。

数据范围

\(1\leq N\leq10^5,~1\leq Q\leq10^5,~V\leq10^3,~a_i \leq10^8,~a \leq10^7,~1\leq l\leq r \leq N\)

只需要把 \(10^7\) 以内的素数筛一遍,然后维护线段树就可以了。

具体地,我们维护 \(\mathrm{val}\)\(\mathrm{sum}\) 分别表示区间覆盖的值和答案,

那么单点修改就是 \(\mathrm{val} \gets \mathrm{val} + k, ~\mathrm{sum} \gets [(\mathrm{val} + k) \in \mathbb{P}]\)

区间推平就是 \(\mathrm{val} \gets k, ~\mathrm{sum} \gets[k \in\mathbb{P}] \times (r - l + 1)\) ,其中 \([x \in \mathbb{P}]\) 表示 \(x\) 属于 \(10^7\) 以内的质数。

时间复杂度 \(\mathcal{O}(10^7 + Q\log N)\)

代码:(直接搬的题解)

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 4e5 + 5, MX = 1e7;
bool flag[MX + 5];
int prime[MX + 5], cur;
void euler() //欧拉筛 
{
	flag[0] = flag[1] = true;
	for (int i = 2; i <= MX; i++)
	{
		if (!flag[i]) prime[++cur] = i;
		for (int j = 1; j <= cur; j++)
		{
			if (i * prime[j] > MX) break;
			flag[i * prime[j]] = true;
			if (i % prime[j] == 0) break;
		}
	}
}
bool isp(int x) {return x <= MX && !flag[x];}
struct SegmentTree
{
	int sum[N], cov[N];
	inline int ls(int x) {return x << 1;}
	inline int rs(int x) {return x << 1 | 1;}
	void pushup(int pos) {sum[pos] = sum[ls(pos)] + sum[rs(pos)];}
	void build(int l, int r, int pos)
	{
		if (l == r)
		{
			cin >> cov[pos];
			sum[pos] = isp(cov[pos]);
			return;
		}
		int mid = (l + r) >> 1;
		build(l, mid, ls(pos)), build(mid + 1, r, rs(pos));
		pushup(pos);
	}
	void lazy(int l, int r, int pos, int k)
	{
		sum[pos] = isp(k) * (r - l + 1);
		cov[pos] = k;
	}
	void pushdown(int l, int r, int pos)
	{
		if (!cov[pos]) return;
		int mid = (l + r) >> 1;
		lazy(l, mid, ls(pos), cov[pos]);
		lazy(mid + 1, r, rs(pos), cov[pos]);
		cov[pos] = 0;
	}
	void update(int l, int r, int pos, int id, int k) //单点加 
	{
		if (l == r)
		{
			cov[pos] += k, sum[pos] = isp(cov[pos]);
			return;
		}
		pushdown(l, r, pos);
		int mid = (l + r) >> 1;
		if (id <= mid) update(l, mid, ls(pos), id, k);
		else update(mid + 1, r, rs(pos), id, k);
		pushup(pos);
	}
	void modify(int l, int r, int pos, int L, int R, int k) //区间推平 
	{
		if (L <= l && r <= R) return lazy(l, r, pos, k);
		pushdown(l, r, pos);
		int mid = (l + r) >> 1;
		if (L <= mid) modify(l, mid, ls(pos), L, R, k);
		if (mid < R) modify(mid + 1, r, rs(pos), L, R, k);
		pushup(pos);
	}
	int query(int l, int r, int pos, int L, int R)
	{
		if (L <= l && r <= R) return sum[pos];
		pushdown(l, r, pos);
		int mid = (l + r) >> 1, ans = 0;
		if (L <= mid) ans += query(l, mid, ls(pos), L, R);
		if (mid < R) ans += query(mid + 1, r, rs(pos), L, R);
		return ans;
	}
} seg;
int main()
{
	ios::sync_with_stdio(false);
	euler();
	int n, T;
	cin >> n >> T;
	seg.build(1, n, 1);
	while (T--)
	{
		char c;
		cin >> c;
		if (c == 'A')
		{
			int k, id;
			cin >> k >> id;
			seg.update(1, n, 1, id, k);
		}
		else if (c == 'R')
		{
			int k, l, r;
			cin >> k >> l >> r;
			seg.modify(1, n, 1, l, r, k);
		}
		else if (c == 'Q')
		{
			int l, r;
			cin >> l >> r;
			cout << seg.query(1, n, 1, l, r) << '\n';
		}
	}
	return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/liangbowen/solution-sp19568


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录