SP19568 PRMQUER - Prime queries
PRMQUER - Prime queries
题面翻译
题目描述
这是一个简单的题目
给定 \(N\) 个数,你需要对它们依次进行 \(Q\) 次操作。每次操作的格式如下。
- 三个整数 \(A\) \(V\) \(l\) 表示给第 \(l\) 个数加上 \(V\) 。
- 四个整数 \(R\) \(a\) \(l\) \(r\) 表示把区间 \([l,r]\) 的数都变为 \(a\) 。
- 三个整数 \(Q\) \(l\) \(r\) 表示询问区间 \([l,r]\) 里,小于等于 \(10^7\) 的素数有多少个。
数据保证任何时刻这 \(N\) 个数都不会有一个数大于 \(10^9\) 。
数据范围
- \(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\)
输入格式
第一行两个整数 \(N\) 和 \(Q\) 分别表示数的个数和操作的个数,第二行有 \(N\) 个整数,表示这些数的初始大小。之后 \(Q\) 行每行一次操作,输入格式如题目描述所述。
输出格式
对于每个操作 \(3\) 输出一行整数表示这个操作的答案。
题目描述
You are given a simple task.
Given a sequence A[i] with N numbers s.t. 1 <= i <= N. You have to perform Q operations on a given set of numbers.
Operations:
A V l
, Add the value V to element with index l.R a l r
, Replace all the elements of sequence with index i s.t. l <= i <= r with a.Q l r
, Print the Number of elements with index i s.t. l <= i <= r and A[i] is prime number and A[i] <= 10^7.
No Number In sequence ever will exceed 10^9.
输入格式
First line contains N as Number of sequence elements && Q as number of operations to be performed. Second line contains Initial N elements of the sequence. After that each of the next Q lines contains one operation to be performed on the sequence.
输出格式
Print each value in newline as stated above.
样例 #1
样例输入 #1
5 10
1 2 3 4 5
A 3 1
Q 1 3
R 5 2 4
A 1 1
Q 1 1
Q 1 2
Q 1 4
A 3 5
Q 5 5
Q 1 5
样例输出 #1
2
1
2
4
0
4
Solution
SP13015 双倍经验(甚至还少了单点修改的操作)
既然有区间推平的操作那就用珂朵莉树水一水吧(逃
区间推平操作是珂朵莉树自带的,所以就不在这里详细阐述了,先来看单点修改怎么做(我最开始看成区间加了所以用区间加实现的)。单点加可以看作一个长度为 \(1\) 的区间进行区间加操作,假设点的位置为 \(pos\) 那么就可以看作 \([pos,pos]\) 这个区间的区间加操作,直接取出区间对这个区间的 \(v\) 值进行加法操作即可。
然后是查询。注意到询问的质数范围是 \((0,10^7]\) 这一数量级的,所以可以先用质数筛法筛出 \(10^7\) 内的质数(我用的埃筛实现的),那么对于一个询问区间 \([l,r]\) ,先将这个区间取出,然后依次扫描这个区间内珂朵莉树的节点,如果当前节点的 \(v\) 值是符合条件的质数,那么这个区间就会对答案产生 \(r-l+1\) 的贡献,统计这个贡献即可。
另外需要注意的是,节点的 \(v\) 值可能会超过 \(10^7\) ,所以直接调用质数数组可能导致下标越界,所以要先判断。
Code
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;
template<typename T> void read(T &k)
{
k=0;T flag=1;char b=getchar();
while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
while (isdigit(b)) {k=k*10+b-48;b=getchar();}
k*=flag;
}
const int _MAXN=1e7,_SIZE=1e5;
bool prime[_MAXN+5];
void preWork()//埃筛
{
prime[1]=1;
for (int i=2;i<=_MAXN;i++)
if (!prime[i])
for (int j=2;j*i<=_MAXN;j++)
prime[j*i]=1;
}
struct NODE{//珂朵莉树
int l,r;
mutable int v;
NODE (int l,int r=0,int v=0) : l(l),r(r),v(v) {}
bool operator< (const NODE &a) const {return l<a.l;}
};
set <NODE> ctlt;
auto split(int pos)
{
auto it=ctlt.lower_bound(NODE(pos));
if (it!=ctlt.end() && it->l==pos) return it;
it--;
if (it->r<pos) return ctlt.end();
int l=it->l,r=it->r,v=it->v;
ctlt.erase(it);
ctlt.insert(NODE(l,pos-1,v));
return ctlt.insert(NODE(pos,r,v)).first;
}
void assign(int l,int r,int x)
{
auto itr=split(r+1),itl=split(l);
ctlt.erase(itl,itr);
ctlt.insert(NODE(l,r,x));
}
void modify(int l,int r,int v)//区间加(用于实现单点加)
{
auto itr=split(r+1),itl=split(l);
for (auto it=itl;it!=itr;it++) it->v+=v;
}
int query(int l,int r)//区间查询
{
auto itr=split(r+1),itl=split(l);
int res=0;
for (auto it=itl;it!=itr;it++)
if (it->v<=10000000 && !prime[it->v]) res+=it->r-it->l+1;//需要注意v值可能大于1e7,直接查看数组会导致下标越界,所以先进行判断
return res;
}
int n,q;
int a[_SIZE+5];
int main()
{
preWork();
read(n),read(q);
for (int i=1;i<=n;i++) read(a[i]),ctlt.insert(NODE(i,i,a[i]));//读入+建树
for (int i=1;i<=q;i++)
{
char op[2];scanf("%s",op);
if (op[0]=='A')
{
int pos,x;
read(x),read(pos);
modify(pos,pos,x);
}
else if (op[0]=='R')
{
int l,r,x;
read(x),read(l),read(r);
assign(l,r,x);
}
else
{
int l,r;
read(l),read(r);
printf("%d\n",query(l,r));
}
}
return 0;
}