zoj3886--Nico Number(素数筛+线段树)

Nico Number


Time Limit: 2 Seconds      Memory Limit: 262144 KB



Kousaka Honoka and Minami Kotori are playing a game about a secret of Yazawa Nico.

When the game starts, Kousaka Honoka will
give Minami Kotori an array A of N non-negative
integers. There is a special kind of number in the array, which is called NicoNico-number.
We call a integer x is a NicoNico-number,
if all integers(no more than x) that is coprime with x could
form an Arithmetic Sequence.

Then Minami Kotori will
choose some consecutive part of the array A, wondering the number of NicoNico-number in
this part. What‘s more, Kousaka Honoka sometimes modify the value of some consecutive elements
in the array. Now it is your task to simulate this game!

Input

There are multiple test cases in input, you should process to the end of file.

For each case, the first line is an integer N, the number of elements in the array described above. Then second line contains N integers no greater than 107,
the elements of the array initially.(1 <= N <= 100,000)

The third line is a integer T, the number of the operations of the game. Each line of the following T lines is in one of the following formats.(1 <= T <= 100,000)

"1 L R" : Minami Kotori will chooses the consecutive part of the array from the Lth to Rth element inclusive. (1 <= L <= R <= N)

"2 L R v" : Kousaka Honoka will change the value of the pth element A[p] in the array to A[p]%v for all L <= p <= R.(1 <= L <=
R <= N, 1 <= v <= 107
)

"3 p x" : Kousaka Honoka will change the value of the p th element A[p] to x.(1 <= p <= N, 1 <= x <= 107)

Output

Each time when Minami Kotori chooses some part of the array, you should output a line, the number of NicoNico-number in that part.

Sample Input

3
4 6 9
6
1 1 3
1 3 3
2 1 1 10
1 1 3
3 2 4
1 1 3

Sample Output

2
0
2
2

Hint

4 is a NicoNico-number because only 1 and 3 is coprime with 4 among the integers no greater than 4, and could form an Arithmetic Sequence {1,3}.

题目大意:定义一个NicoNico-number,假设x是NicoNico-number,那么全部小于x的且与x互质的整数是一个等差数列,初始给出n个数字的数组,三种操作:

1 l r 问在[l,r]内有多少个NicoNico-number数

2 l r v 对于[l,r]内的数所有对v取余

3 k x 将第k个数换为x

对每一次询问做出输出。

1、首先写一个找规律的,发现NicoNico-number是有三种组成的第一种是素数,另外一种是2的x次幂,第三种是6

2、那么能够建一个数组。直接标记某个数是不是NicoNico-number

3、使用线段树维护一段区间的NicoNico-number个数,然后能够进行对某一个数的改动,和对一个区间的查询。

对于另外一种操作。我们要知道对于一个数x取余操作。最多会运行log(x)次。由于每次取余至少数值会降低一半。所以对于每一个数来说最多会有log(x)次操作,之后会由于v大于当前值,而不用运行操作。既然取余的次数不多,那么就能够对区域操作进行暴力,维护一段区间的最大值,假设最大值小于v,那么这一段不用更新,否则就遍历的最低层进行取余。

4、对于n个数来说,查找到一个数须要log(n),一个数最多会被改动log(x)次,所以总的时间不会超过n*log(n)*log(x)。

#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
#include <algorithm>
using namespace std ;
#define LL __int64
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define root 1,n,1
#define int_rt int l,int r,int rt
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
const int mod = 1e9+7 ;
const double eqs = 1e-9 ;
int cl[400000] , num[400000] ;
int a[10000005] , check[10000005] ;
int tot ;
void init() {
    memset(check,-1,sizeof(check)) ;
    tot = 0 ;
    for(int i = 2 ; i <= 10000000 ; i++) {
        if( check[i] == -1 ){
            a[tot++] = i ;
            check[i] = 1 ;
        }
        for(int j = 0 ; j < tot ; j++) {
            if( i*a[j] >= 10000000 ) break ;
            check[i*a[j]] = 0 ;
            if( i%a[j] == 0 ) break ;
        }
    }
    check[0] = check[1] = check[6] = 1 ;
    for(int i = 2 ; i <= 10000000 ; i *= 2)
        check[i] = 1 ;
}
void push_up(int rt) {
    cl[rt] = max(cl[rt<<1],cl[rt<<1|1]) ;
    num[rt] = num[rt<<1]+num[rt<<1|1] ;
}
void create(int_rt) {
    cl[rt] = num[rt] = 0 ;
    if( l == r ) {
        scanf("%d", &cl[rt]) ;
        if( check[ cl[rt] ] == 1 ) num[rt] = 1 ;
        return ;
    }
    create(lson) ;
    create(rson) ;
    push_up(rt) ;
}
void update1(int ll,int rr,int v,int_rt) {
    if( ll > r || rr < l ) return ;
    if( cl[rt] < v ) return ;
    if( l == r ) {
        cl[rt] %= v ;
        if( check[ cl[rt] ] == 1 ) num[rt] = 1 ;
        else num[rt] = 0 ;
        return ;
    }
    update1(ll,rr,v,lson) ;
    update1(ll,rr,v,rson) ;
    push_up(rt) ;
}
void update2(int k,int x,int_rt) {
    if( l == r && l == k ) {
        cl[rt] = x ;
        if( check[ cl[rt] ] == 1 ) num[rt] = 1 ;
        else num[rt] = 0 ;
        return ;
    }
    int mid = (l+r)/2 ;
    if(k <= mid) update2(k,x,lson) ;
    else update2(k,x,rson) ;
    push_up(rt) ;
}
int query(int ll,int rr,int_rt) {
    if( ll > r || rr < l ) return 0 ;
    if( ll <= l && rr >= r ) return num[rt] ;
    return query(ll,rr,lson) + query(ll,rr,rson) ;
}
int main() {
    int n , m , i , k , l , r , v , x ;
    init() ;
    while( scanf("%d", &n) !=EOF ) {
        create(root) ;
        scanf("%d", &m) ;
        while( m-- ) {
            scanf("%d", &k) ;
            if( k == 1 ) {
                scanf("%d %d", &l, &r) ;
                printf("%d\n", query(l,r,root)) ;
            }
            else if( k == 2 ) {
                scanf("%d %d %d", &l, &r, &v) ;
                update1(l,r,v,root) ;
            }
            else {
                scanf("%d %d", &i, &x) ;
                update2(i,x,root) ;
            }
        }
    }
    return 0 ;
}
时间: 2025-01-31 04:11:52

zoj3886--Nico Number(素数筛+线段树)的相关文章

HDU 1394 Minimum Inversion Number (数据结构-线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9514    Accepted Submission(s): 5860 Problem Description The inversion number of a given number sequence a1, a2, ..., an

ZOJ 3886 Nico Number(筛素数+Love(线)Live(段)树)

problemCode=3886">ZOJ 3886 题意: 定义一种NicoNico数x,x有下面特征: 全部不大于x且与x互质的数成等差数列,如x = 5 ,与5互素且不大于5的数1,2,3,4成等差数列.则5是一个NicoNico数. 再定义三种操作: 1.南小鸟询问[L, R]内有多少个NicoNico数: 2.果皇把[L, R]内的数全部对v取余: 3.果皇将第K个数换成X. 然后给你一个数列,并对这个数列运行若干操作 思路: 这样的问题果断要用LoveLive树线段树来做! 首

POJ-2104-K-th Number(可持久化线段树)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 55456   Accepted: 19068 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

ACM Minimum Inversion Number 解题报告 -线段树

C - Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.

HDU 1394 &lt;Minimum Inversion Number&gt; &lt;逆序数&gt;&lt;线段树&gt;

Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seq

HDU_3071 Gcd &amp; Lcm game 【素数分解 + 线段树 + 状压】

一.题目  Gcd & Lcm game 二.分析 非常好的一题. 首先考虑比较暴力的做法,肯定要按区间进行处理,对于$lcm$和$gcd$可以用标准的公式进行求,但是求$lcm$的时候是肯定会爆$long long$的. 考虑用素数分解,将所有的数分解后,发现素因子的个数有限,且每个因子的幂也有限,最多的也就是$2^_6$,然后可以考虑将素因子用二进制的每一位进行表示.对于$2,3,5,7$可能会要的多点,所以多给给几位就可以了,最后发现,刚好可以$32$位以内. 这里就需要写两个转换函数,然

HDU 2665 Kth number 可持久化线段树

题意:给n个数和m个询问,询问l,r,k是从l~r中的第k小 思路:可持久化线段树的模板题 说下自己对可持久化线段树的理解吧 可持久化线段树的是可以保存历史版本的线段树,就是插进去第i个数的线段树的状态,这样我们可以通过state[r]-state[l-1]来得到state[l~r] 朴素做法就是维护n颗线段树,但是这样一般都会MLE 可持久化线段树利用了每次插入数只修改了线段树上一条链的特性来每次插入一个数只新建一条链来维护历史版本,空间复杂度O(n*logn+n*logn) 原树+新建的链

FZU 2297 Number theory【线段树/单点更新/思维】

Given a integers x = 1, you have to apply Q (Q ≤ 100000) operations: Multiply, Divide. Input First line of the input file contains an integer T(0 < T ≤ 10) that indicates how many cases of inputs are there. The description of each case is given below

埃氏筛+线段树——cf731F

从2e5-1依次枚举每个数作为主显卡,然后分段求比它大的数的个数,这里的复杂度是调和级数ln2e5,即埃氏筛的复杂度.. #include<bits/stdc++.h> using namespace std; #define ll long long #define N 200005 int cnt[N],n; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll num[N<<2]; void upda