CF920F SUM and REPLACE 题解

CF920F SUM and REPLACE

线段树例题解析合集

和模板的不同之处在于修改时是改为每个数的约数个数,不难发现,当一个数x<=2时,x的约数个数与本身相等,修改多少次多不会在改变

先预处理出每个数的约数个数,用线段树维护区间最大值,若<=2,则直接结束递归

对于>2的数都要暴力修改,但由于每个数的约数个数下降很快,几次后便降到<=2,所以复杂度优秀(大约是nlogn?)

这题与CF438D The Child and Sequence(区间取模),类似,也可以维护区间最大值

CF920F:

#include <bits/stdc++.h>
using namespace std;
#define rg register
#define ll long long
inline void read (int &x) {
    char ch = getchar(); x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch))  x = x * 10 + ch - 48, ch = getchar();
}
void print (ll x) {
    if (x > 9) print (x / 10);
    putchar (x % 10 + 48);
}
const int N = 3e5 + 10, M = 1e6;
int n, m, opt, ql, qr, cnt, maxn, p[N], a[N], k[M + 10], num[M + 10], c[N << 2];
ll s[N << 2];
inline void pre_work () {
    num[1] = 1;
    for (rg int i = 2; i <= maxn; ++i) {
        if (!k[i]) p[++cnt] = i, num[i] = 2;
        for (rg int j = 1; j <= cnt && p[j] * i <= maxn; ++j) {
            int tmp (p[j] * i), t (0);
            while (tmp % p[j] == 0) ++t, tmp /= p[j];
            k[p[j] * i] = 1, num[p[j] * i] = num[tmp] * (t + 1);
            if (i % p[j] == 0) continue;
        }
    }
}
#define ls p << 1
#define rs p << 1 | 1
inline int Max (int a, int b) {return a > b ? a : b;}
inline void push_up (int p) {
    s[p] = s[ls] + s[rs], c[p] = Max (c[ls], c[rs]);
}
void build (int p, int l, int r) {
    if (l == r) {c[p] = s[p] = a[l]; return;}
    int mid = l + r >> 1;
    build (ls, l, mid), build (rs, mid + 1, r);
    push_up (p);
}
void update (int p, int l, int r) {
    if (c[p] <= 2) return;
    if (l == r) {c[p] = s[p] = num[c[p]]; return;}
    int mid = l + r >> 1;
    if (ql <= mid) update (ls, l, mid);
    if (qr > mid) update (rs, mid + 1, r);
    push_up (p);
}
ll ask (int p, int l, int r) {
    if (ql <= l and qr >= r) return s[p];
    ll s (0);  int mid = l + r >> 1;
    if (ql <= mid) s += ask (ls, l, mid);
    if (qr > mid) s += ask (rs, mid + 1, r);
    return s;
}
int main() {
    read (n), read (m);
    for (rg int i = 1; i <= n; ++i) read (a[i]), maxn = Max (maxn, a[i]);
    pre_work (), build (1, 1, n);
    for (rg int i = 1; i <= m; ++i) {
        read (opt);
        if (opt == 1) read (ql), read (qr), update (1, 1, n);
        else read (ql), read (qr), print (ask (1, 1, n)), puts ("");
    }
    return 0;
}

CF438D:

#include <bits/stdc++.h>
using namespace std;
#define rg register
#define ll long long
inline void read (int &x) {
    char ch = getchar(); x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch))  x = x * 10 + ch - 48, ch = getchar();
}
void print (ll x) {
    if (x > 9) print (x / 10);
    putchar (x % 10 + 48);
}
const int N = 1e5 + 10;
int n, m, opt, ql, qr, mod, val, pos, a[N], c[N << 2];
ll s[N << 2];
#define ls p << 1
#define rs p << 1 | 1
inline int Max (int a, int b) {return a > b ? a : b;}
inline void push_up (int p) {
    s[p] = s[ls] + s[rs], c[p] = Max (c[ls], c[rs]);
}
void build (int p, int l, int r) {
    if (l == r) {c[p] = s[p] = a[l]; return;}
    int mid = l + r >> 1;
    build (ls, l, mid), build (rs, mid + 1, r);
    push_up (p);
}
void update (int p, int l, int r) {
    if (c[p] < mod) return;
    if (l == r) {c[p] %= mod, s[p] %= mod; return;}
    int mid = l + r >> 1;
    if (ql <= mid) update (ls, l, mid);
    if (qr > mid) update (rs, mid + 1, r);
    push_up (p);
}
void change (int p, int l, int r) {
    if (l == r) {c[p] = s[p] = val; return;}
    int mid = l + r >> 1;
    (pos <= mid) ? change (ls, l, mid) : change (rs, mid + 1, r);
    push_up (p);
}
ll ask (int p, int l, int r) {
    if (ql <= l and qr >= r) return s[p];
    ll s (0);  int mid = l + r >> 1;
    if (ql <= mid) s += ask (ls, l, mid);
    if (qr > mid) s += ask (rs, mid + 1, r);
    return s;
}
int main() {
    read (n), read (m);
    for (rg int i = 1; i <= n; ++i) read (a[i]);
    build (1, 1, n);
    for (rg int i = 1; i <= m; ++i) {
        read (opt);
        if (opt == 1) {
            read (ql), read (qr);
            print (ask (1, 1, n)), puts ("");
        }
        else if (opt == 2) {
            read (ql), read (qr), read (mod);
            update (1, 1, n);
        }
        else {
            read (pos), read (val);
            change (1, 1, n);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/whx666/p/12041522.html

时间: 2024-08-30 15:55:11

CF920F SUM and REPLACE 题解的相关文章

codeforces CF920F SUM and REPLACE 线段树 线性筛约数

$ \Rightarrow $ 戳我进CF原题 F. SUM and REPLACE time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard input output: standard output Let $ D(x) $ be the number of positive divisors of a positive integer $ x $ . For example, $

Codefroces 920F SUM and REPLACE(线段树)

SUM and REPLACE 题意:给你n个数,进行m次操作,分别是将区间[l,r]内的所有数替换成自己的因子数 和 对区间[l,r]进行求和. 题解:可以发现2的因子个数还是2,1的因子个数还是1,所以如果某个数被更新成1或者2之后就不需要再进行更新了. 1 #include<bits/stdc++.h> 2 #define ll long long 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 us

Educational Codeforces Round 37-F.SUM and REPLACE (线段树,线性筛,收敛函数)

F. SUM and REPLACE time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard output Let D(x) be the number of positive divisors of a positive integer x. For example, D(2)?=?2 (2 is divisible by 1 and 2), D(6)?

题解 CF920F 【SUM and REPLACE】

可以事先打表观察每个数的约数个数,观察到如果进行替换,若干次后这个数便会被替换成1. 所以我们可以直接暴力的进行区间修改,若这个数已经到达1或2,则以后就不再修改,用并查集和树状数组进行维护. 这个方法用了P2391 白雪皑皑的思想处理,用并查集标记该点已经不再用替换. code: #include<bits/stdc++.h> #include<cctype> #define maxn 300010 #define lowbit(x) (x&(-x)) typedef l

Codeforces 920F. SUM and REPLACE

题目大意: 一个数列 支持两种操作 1 把区间内的数变成他们自己的约数个数 2 求区间和 思路: 可以想到每个数最终都会变成2或1 然后我们可以线段树 修改的时候记录一下每段有没有全被修改成1或2 是的话就不修改了 不是就暴力修改 因为每个数被修改的次数很小 1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring&g

Lintcode207 Interval Sum II solution 题解

[题目描述] Given an integer array in the construct method, implement two methods query(start, end) and modify(index, value): For query(start,end), return the sum from index start to index end in the given array. For modify(index,value), modify the number

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long

CodeForces - 920F SUM and REPLACE (线段树)

题意:给N个数M次操作,(1<=N,M<=3e5, 1<=ai<=1e6),1是使[L,R]中的每个元素变成其因子的个数之和:2是求[L,R]区间之和 分析:看上去就很线段树的一题,但是却思考了很久.发现1和2即使对其,也不会改变二者的值.而且一个大于2的数进行多次1操作,也最终会退化到2. 先预处理筛出1e6以内各数的质因子个数和.在线段树的节点中维护两个值:区间和以及区间最大值.在update函数中,如果该区间的最大值不超过2,那么该区间没有更新的必要:若超过2,则递归向下找到

题解 SP2713 【GSS4 - Can you answer these queries IV】

用计算器算一算,就可以发现\(10^{18}\)的数,被开方\(6\)次后就变为了\(1\). 所以我们可以直接暴力的进行区间修改,若这个数已经到达\(1\),则以后就不再修改(因为\(1\)开方后还是\(1\)),用并查集和树状数组进行维护. 这个方法用了P2391 白雪皑皑的思想处理,用并查集标记该点已经不再用替换. 和我这题CF920F[SUM和REPLACE]的方法相同. \(code\): #include<bits/stdc++.h> #define maxn 500010 #de