欢迎神犇吊打|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2022-08-07 10:36阅读: 42评论: 0推荐: 0

SP19568 PRMQUER - Prime queries

PRMQUER - Prime queries

SP19568(Luogu)

题面翻译

题目描述

这是一个简单的题目

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

  1. 三个整数 A V l 表示给第 l 个数加上 V
  2. 四个整数 R a l r 表示把区间 [l,r] 的数都变为 a
  3. 三个整数 Q l r 表示询问区间 [l,r] 里,小于等于 107 的素数有多少个。

数据保证任何时刻这 N 个数都不会有一个数大于 109

数据范围

  • 1N105
  • 1Q105
  • V103
  • A[i]108
  • a107
  • 1lrN

输入格式

第一行两个整数 NQ 分别表示数的个数和操作的个数,第二行有 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:

  1. A V l, Add the value V to element with index l.
  2. R a l r, Replace all the elements of sequence with index i s.t. l <= i <= r with a.
  3. 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,107] 这一数量级的,所以可以先用质数筛法筛出 107 内的质数(我用的埃筛实现的),那么对于一个询问区间 [l,r] ,先将这个区间取出,然后依次扫描这个区间内珂朵莉树的节点,如果当前节点的 v 值是符合条件的质数,那么这个区间就会对答案产生 rl+1 的贡献,统计这个贡献即可。

另外需要注意的是,节点的 v 值可能会超过 107 ,所以直接调用质数数组可能导致下标越界,所以要先判断。

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;
}
posted @   Hanx16Msgr  阅读(42)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起