您的位置:首页 > 其它

ZOJ 3886 Nico Number(线段树单点更新+找规律)

2015-08-10 16:33 295 查看

题意:

定义一个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)n*log(n)*log(x)。

mymy codecode

[code]#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int MAXX = (int)1e7 + 5;
const int MAXN = (int)1e5 + 5;
bool nico[MAXX*2];
int A[MAXN];
int n, q;

void prepare() {
    memset(nico, true, sizeof(nico));
    for(int i = 2; i < MAXX; i++) {
        if(!nico[i]) continue;
        nico[i] = true;
        for(int j = i*2; j < MAXX; j += i) {
            nico[j] = false;
        }
    }
    nico[6] = true;
    for(int i = 1; i < MAXX; i <<= 1) {
        nico[i] = true;
    }
}

int maxv[MAXN << 2], sumv[MAXN << 2];

void pushUp(int o) {
    maxv[o] = max(maxv[ls], maxv[rs]);
    sumv[o] = sumv[ls] + sumv[rs];
}

void build(int o, int L, int R) {
    if(L == R) {
        maxv[o] = A[L];
        sumv[o] = nico[A[L]];
        return ;
    }
    int M = (L + R)/2;
    build(lson);
    build(rson);
    pushUp(o);
}

int query(int o, int L, int R, int ql, int qr) {
    if(ql <= L && R <= qr)
        return sumv[o];
    int M = (L + R)/2, ret = 0;
    if(ql <= M) ret += query(lson, ql, qr);
    if(qr > M) ret += query(rson, ql, qr);
    return ret;
}

void setValue(int o, int L, int R, int pos, int val) {
    if(L == R) {
        sumv[o] = nico[val];
        maxv[o] = val;
        return ;
    }
    int M = (L + R)/2;
    if(pos <= M) setValue(lson, pos, val);
    else setValue(rson, pos, val);
    pushUp(o);
}

void modify(int o, int L, int R, int ql, int qr, int val) {
    if(ql <= L && R <= qr && val > maxv[o])
        return ;
    if(L == R) {
        maxv[o] %= val;
        sumv[o] = nico[maxv[o]];
        return ;
    }
    int M = (L + R)/2;
    if(ql <= M) modify(lson, ql, qr, val);
    if(qr > M) modify(rson, ql, qr, val);
    pushUp(o);
}

int main() {
    prepare();
    while(scanf("%d", &n) != EOF) {
        for(int i = 1; i <= n; i++) {
            scanf("%d", &A[i]);
        }
        build(1, 1, n);
        scanf("%d", &q);
        int oper, ql, qr, val;
        while(q--) {
            scanf("%d", &oper);
            if(oper == 1) {
                scanf("%d%d", &ql, &qr);
                printf("%d\n", query(1, 1, n, ql, qr));
            }else if(oper == 2) {
                scanf("%d%d%d", &ql, &qr, &val);
                modify(1, 1, n, ql, qr, val);
            }else {
                scanf("%d%d", &ql, &val);
                setValue(1, 1, n, ql, val);
            }
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: