题解 SP19568 【PRMQUER - Prime queries】
posted on 2021-07-10 20:00:18 | under 题解 | source
观察题目,发现它说了这么多其实是想让我们写一个数据结构支持:
- 单点修改(区间长为 \(1\) 的区间修改);
- 区间赋值;
- 区间计算 \(<10^7\) 的素数个数。
看到"区间赋值"这个操作,我们不难想到 Old Driver Tree 这一暴力数据结构。本题数据较水,所以使用 Old Driver Tree 是可以通过的,大胆去写吧。
另外,题目已经说了素数最大 \(10^7\),为了更容易通过,最好使用线性筛预处理出所有素数,然后每次 \(O(1)\) 判断素数。
下面给出我的代码实现:
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
template<int N> struct LS{//线性筛板子
//https://www.luogu.com.cn/blog/cicos/notprime
int p[N+10],n;
bool isnp[N+10];
LS(){
isnp[0]=isnp[1]=1;
for(int i=2;i<=N;i++){
if(!isnp[i]) p[++n]=i;
for(int j=1;j<=n&&i*p[j]<=N;j++){
if(isnp[i*p[j]]=1,i%p[j]==0) break;
//上面这个是逗号表达式,固定从左往右,返回最后一个值
}
}
}
bool operator()(int x){return !isnp[x];}
};
LS<10000000> p;
// 1234567 个 0 别数错了
template<class T> struct ODT{
struct node{
int l,r;
mutable T v;
operator int()const{return r-l+1;}
//https://zh.cppreference.com/w/cpp/language/cast_operator
//注意 const 不能少
node(int l,int r=-1,T v=0):l(l),r(r),v(v){}
bool operator<(const node &b)const{return l<b.l;}
};
set<node> s;
typedef typename set<node>::iterator IT;
void init(int n,T a[]){
s.insert(node(n+1,n+1));
for(int i=1;i<=n;i++) s.insert(node(i,i,a[i]));
}
IT split(int pos){
IT it=s.lower_bound(node(pos));
if(it!=s.end()&&it->l==pos) return it;
T v=(--it)->v;
//如果你像我一样压行,一定要注意优先级问题,--it 加一对括号
int l=it->l,r=it->r;
s.erase(it);
s.insert(node(l,pos-1,v));
return s.insert(node(pos,r,v)).first;
}
void assign(int l,int r,T v){
IT R=split(r+1),L=split(l);
s.erase(L,R);
s.insert(node(l,r,v));
}
void add(int l,int r,T v){
IT R=split(r+1),L=split(l);
for(IT it=L;it!=R;++it) it->v+=v;
}
int query(int l,int r){
int ans=0;
IT R=split(r+1),L=split(l);
for(IT it=L;it!=R;++it) ans+=p(min(it->v,10000000))*(*it);
//同样 (*it) 的括号也不能少
return ans;
}
void output(){
for(IT it=s.begin();it!=s.end();++it){
for(int i=it->l;i<=it->r;i++){
cout<<it->v<<" |"[i==it->r];
}
}
cout<<endl;
}
};
ODT<int> a;
int n,m,ipu[100010];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>ipu[i];
a.init(n,ipu);
for(int i=1;i<=m;i++){char op;
cin>>op;
//或 scanf(" %c",&op),注意空格
if(op=='A'){
int l,v;
cin>>v>>l;//注意输入格式
a.add(l,l,v);
}else if(op=='R'){
int l,r,v;
cin>>v>>l>>r;
a.assign(l,r,v);
}else{
int l,r;
cin>>l>>r;
cout<<a.query(l,r)<<endl;
}
//a.output();
}
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/solution-SP19568.html