【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 long LL;
const int N = 300005;
const int M = 1000005;
int a[N];
int lch[N << 2], rch[N << 2];
LL sum[N << 2], Max[N << 2];
LL prime[M], e[M], d[M];
int check[M], cnt;
void seive() {
    memset(check, 0, sizeof(check)); cnt = 0; d[1] = 1; e[1] = 1;
    for(int i = 2; i < M; ++i) {
        if(!check[i]) {prime[cnt++] = i; e[i] = 1; d[i] = 2;}
        for(int j = 0; j < cnt; ++j) {
            if(1LL * i * prime[j] >= M) break;
            check[i * prime[j]] = 1;
            if(i % prime[j] == 0) {
                e[i * prime[j]] = e[i] + 1;
                d[i * prime[j]] = d[i] / (e[i] + 1) * (e[i] + 2);
                break;
            }else {
                d[i * prime[j]] = d[i] * 2; e[i * prime[j]] = 1;
            }
        }
    }
}
inline void pushup(int x) {
    sum[x] = sum[x << 1] + sum[x << 1 | 1];
    Max[x] = max(Max[x << 1], Max[x << 1 | 1]);
}
void build(int x, int l, int r) {
    lch[x] = l; rch[x] = r; sum[x] = Max[x] = 0;
    if(l == r) {
        sum[x] = Max[x] = a[l]; return;
    }
    int mid = (l + r) / 2;
    build(x << 1, l, mid); build(x << 1 | 1, mid + 1, r);
    pushup(x);
}
void update(int x, int l, int r) {
    if(Max[x] <= 2) return;
    if(lch[x] == rch[x]) {
        sum[x] = Max[x] = d[sum[x]]; return;
    }
    int mid = (lch[x] + rch[x]) / 2;
    if(r <= mid) update(x << 1, l, r);
    else if(l > mid) update(x << 1 | 1, l, r);
    else update(x << 1, l, mid), update(x << 1 | 1, mid + 1, r);
    pushup(x);
}
LL query(int x, int l, int r) {
    if(l == lch[x] && rch[x] == r) return sum[x];
    int mid = (lch[x] + rch[x]) / 2;
    if(r <= mid) return query(x << 1, l, r);
    else if(l > mid) return query(x << 1 | 1, l, r);
    else return query(x << 1, l, mid) + query(x << 1 | 1, mid + 1, r);
}
int n, m, t, l, r;
int main() {
    seive();
    // for (int i = 1; i < M; i++)
    //     for (int j = i; j < M; j += i) d[j]++;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    build(1, 1, n);
    for(int i = 1; i <= m; ++i) {
        scanf("%d%d%d", &t, &l, &r);
        if(t == 1) update(1, l, r);
        else printf("%I64d\n", query(1, l, r));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ogiso-setsuna/p/8455392.html

时间: 2024-08-07 00:51:14

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛的相关文章

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

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, $

Educational Codeforces Round 64 (Rated for Div. 2) (线段树二分)

题目:http://codeforces.com/contest/1156/problem/E 题意:给你1-n  n个数,然后求有多少个区间[l,r] 满足    a[l]+a[r]=max([l,r]) 思路:首先我们去枚举区间肯定不现实,我们只能取把能用的区间去用,我们可以想下每个数当最大值的时候所做的贡献 我们既然要保证这个数为区间里的最大值,我们就要从两边扩展,找到左右边界能扩展在哪里,这里你直接去枚举肯定不行 这里我们使用了线段树二分去枚举左右区间最远能走到哪里,然后很暴力的去枚举短

Educational Codeforces Round 21 F. Card Game(网络流之最大点权独立集)

题目链接:Educational Codeforces Round 21 F. Card Game 题意: 有n个卡片,每个卡片有三个值:p,c,l; 现在让你找一个最小的L,使得满足选出来的卡片l<=L,并且所有卡片的p的和不小于k. 选择卡片时有限制,任意两张卡片的c之和不能为质数. 题解: 和hdu 1565 方格取数(2)一样,都是求最大点权独立集. 不难看出来,这题再多一个二分. 注意的是在构造二部图的时候,按照c值的奇偶性构造. 当c==1时要单独处理,因为如果有多个c==1的卡片,

Educational Codeforces Round 37

Educational Codeforces Round 37 题面 题目详见CodeForces 先大概的写个翻译... A 有一个长度为\(n\)的花园 有\(K\)个水龙头, 假设水龙头的位置在\(x\) \(1s\)后\(x\)会被灌溉 \(2s\)后\([x-1,x+1]\)会被灌溉 \(js\)后\([x-j+1,x+j-1]\)会被灌溉 问这个花园在什么时候会被灌溉完 B 阅读理解题,我英语不好呀... 有\(n\)个人要去喝茶 每个人有一个\(l,r\) 表示这个人会在第\(ls

Educational Codeforces Round 76 F 折半枚举

Educational Codeforces Round 76 F 折半枚举 https://codeforces.com/contest/1257/problem/F 题意: 数组a,找到一个x使得a中每一个元素异或x后"二进制中1的个数"相同. 数组长度100,数字大小2^30. 思路: 折半枚举答案X,如分为X前15位和后15位.之后我们再枚举期望的"相同个数"是多少,通过hash看看能不能满足就好了. 代码: #include <bits/stdc++

Educational Codeforces Round 25 F. String Compression(kmp+dp)

题目链接:Educational Codeforces Round 25 F. String Compression 题意: 给你一个字符串,让你压缩,问压缩后最小的长度是多少. 压缩的形式为x(...)x(...)  x表示(...)这个出现的次数. 题解: 考虑dp[i]表示前i个字符压缩后的最小长度. 转移方程解释看代码,这里要用到kmp来找最小的循环节. 当然还有一种找循环节的方式就是预处理lcp,然后通过枚举循环节的方式. 这里我用的kmp找的循环节.复杂度严格n2. 1 #inclu

Educational Codeforces Round 24 F. Level Generation(三分)

题目链接:Educational Codeforces Round 24 F. Level Generation 题意: 给你n个点,让你构造ans条边,使得这ans条边中至少有一半是桥. 让你求ans的最大值. 题解: 首先我们将每一个点按顺序连起来,那么可以构成n-1个桥. 然后我们可以把其中的x个点拿出来连边,这些边都不是桥. x个点最多能连x*(x-1)条边,然后剩下的n-x个点连的边将会构成桥. 然后就可以构造一个函数关系,详见check函数,然后三分一下就行了. 1 #include

Educational Codeforces Round 37 (Rated for Div. 2)A,B,C,F

A Water The Garden 数据不大,暴力模拟下直至把每个花床都遍历过的过程即可 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define PI acos(-1.0) 5 #define INF 1e18 6 #define inf 0x3f3f3f3f 7 #define FAST_IO ios::sync_with_stdio(false) 8 9 const int N=456; 10 typedef long