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)?=?4 (6 is divisible by 1, 2, 3 and 6).

You are given an array a of n integers. You have to process two types of queries:

REPLACE l r — for every replace ai with D(ai);
SUM l r — calculate .
Print the answer for each SUM query.

Input
The first line contains two integers n and m (1?≤?n,?m?≤?3·105) — the number of elements in the array and the number of queries to process, respectively.

The second line contains n integers a1, a2, ..., an (1?≤?ai?≤?106) — the elements of the array.

Then m lines follow, each containing 3 integers ti, li, ri denoting i-th query. If ti?=?1, then i-th query is REPLACE li ri, otherwise it‘s SUM li ri (1?≤?ti?≤?2, 1?≤?li?≤?ri?≤?n).

There is at least one SUM query.

Output
For each SUM query print the answer to it.

Example
inputCopy
7 6
6 4 1 10 3 2 4
2 1 7
2 4 5
1 3 5
2 4 4
1 5 7
2 1 7
outputCopy
30
13
4
22

https://codeforces.com/contest/920/problem/F

题意:

给你一个含有n个数的数组,和m个操作

操作1:将l~r中每一个数\(a[i]\)变成 \(d(a[i])\)

? 其中$ d(x)$ 是约数个数函数。

操作2: 求l~r的a[i] 的sum和。

思路:

$ d(x)$ 约数个数函数可以利用线性筛预处理处理。

又因为 \(d(2)=2\) 和 \(d(1)=1\) 操作1对a[i]等于1或者2没有影响。

那么我们可以对一个区间中全都是1或者2不更新操作。

同时 \(d(x)\) 是收敛函数, 在1e6 的范围内,最多不超过5次改变就会收敛到1或2.

所以更新操作可以暴力解决,

同时用线段树维护即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}

inline void getInt(int *p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
//  d(n)表示n的约数个数和
// prime[i]表示第i个质数
//num[i]表示i的最小质因子出现次数
int sshu[maxn];
int N = maxn;
int num[maxn];
int d[maxn];
bool no[maxn];
int tot;
void prepare()
{
    d[1] = 1; num[1] = 1;
    for (int i = 2; i < N; i++) {
        if (!no[i]) {
            sshu[++tot] = i;
            d[i] = 2; num[i] = 1;
        }
        for (int j = 1; j <= tot && sshu[j]*i < N; j++) {
            int v = sshu[j] * i;
            no[v] = 1;
            if (i % sshu[j] == 0) {
                num[v] = num[i] + 1;
                d[v] = d[i] / num[v] * (num[v] + 1);
                break;
            }
            d[v] = d[i] << 1; num[v] = 1;
        }
    }
    //for (int i=1;i<=10;i++) printf("%d\n",d[i]);
}
int a[maxn];
struct node {
    int l, r;
    int laze;
    bool isall;
    ll num;
} segment_tree[maxn << 2];

void pushup(int rt)
{
    segment_tree[rt].num = segment_tree[rt << 1].num + segment_tree[rt << 1 | 1].num;
    segment_tree[rt].isall = segment_tree[rt << 1].isall & segment_tree[rt << 1 | 1].isall;
}
void build(int rt, int l, int r)
{
    segment_tree[rt].l = l;
    segment_tree[rt].r = r;
    if (l == r) {
        segment_tree[rt].num =a[l];
        if (segment_tree[rt].num == 1 || segment_tree[rt].num == 2) {
            segment_tree[rt].isall = 1;
        }
        return ;
    }
    int mid = (l + r) >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}

void update(int rt, int l, int r)
{
    if (l <= segment_tree[rt].l && r >= segment_tree[rt].r && segment_tree[rt].isall) {
        return;
    }
    if (segment_tree[rt].l == segment_tree[rt].r) {
        segment_tree[rt].num = d[segment_tree[rt].num];
        if (segment_tree[rt].num == 1 || segment_tree[rt].num == 2) {
            segment_tree[rt].isall = 1;
        }
        return ;
    } else {
        int mid = (segment_tree[rt].l + segment_tree[rt].r) >> 1;
        if (mid >= l) {
            update(rt << 1, l, r);
        }
        if (mid < r) {
            update(rt << 1 | 1, l, r);
        }
        pushup(rt);
    }
}
ll query(int rt, int l, int r)
{
    if (segment_tree[rt].l >= l && segment_tree[rt].r <= r) {
        ll res = 0ll;
        res += segment_tree[rt].num;
        return res;
    }
    int mid = (segment_tree[rt].l + segment_tree[rt].r) >> 1;
    ll res = 0ll;
    if (mid >= l) {
        res += query(rt << 1, l, r);
    }
    if (mid < r) {
        res += query(rt << 1 | 1, l, r);
    }
    return res;

}
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    prepare();
    int n, m;
    du2(n, m);
    repd(i, 1, n) {
        du1(a[i]);
    }
    build(1, 1, n);
    repd(i, 1, m) {
        int op; int l, r;
        du3(op, l, r);
        if (op == 1) {
            update(1, l, r);
        } else {
            printf("%lld\n", query(1, l, r));
        }
    }
    return 0;
}

inline void getInt(int *p)
{
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    } else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}

?

原文地址:https://www.cnblogs.com/qieqiemin/p/11617207.html

时间: 2025-01-14 03:07:50

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

【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

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