题解 CF920F 【SUM and REPLACE】

可以事先打表观察每个数的约数个数,观察到如果进行替换,若干次后这个数便会被替换成1。

所以我们可以直接暴力的进行区间修改,若这个数已经到达1或2,则以后就不再修改,用并查集和树状数组进行维护。

这个方法用了P2391 白雪皑皑的思想处理,用并查集标记该点已经不再用替换。

code:

#include<bits/stdc++.h>
#include<cctype>
#define maxn 300010
#define lowbit(x) (x&(-x))
typedef long long ll;
using namespace std;
ll n,m;
ll fa[maxn],k,l,r;
ll a[maxn],tree[maxn*4];
ll d[1000010];
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=x*10+(c^48);c=getchar();}
    if(flag)x=-x;
}
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
void add(int x,ll d)
{
    while(x<=n)
    {
        tree[x]+=d;
        x+=lowbit(x);
    }
}
ll query(int x)
{
    ll sum=0;
    while(x)
    {
        sum+=tree[x];
        x-=lowbit(x);
    }
    return sum;
}
int main()
{
    for(register int i=1;i<=1000000;++i)
    {
        for(register int j=i;j<=1000000;j+=i)
        d[j]++;//将每个数的约数个数预处理出来,便于后面替换
    }
    read(n);
    read(m);
    for(register int i=1;i<=n;++i)
    {
        read(a[i]);
        add(i,a[i]);
        fa[i]=i;
    }
    fa[n+1]=n+1;
    while(m--)
    {

        read(k);
        read(l);
        read(r);
        if(l>r)
        swap(l,r);
        if(k==1)
        {
            for(register int i=l;i<=r;)
            {
                add(i,(ll)d[a[i]]-a[i]);
                a[i]=(ll)d[a[i]];
                if(a[i]<=2)
                fa[i]=i+1;//若这个数已经为1或2,这将其指向它下一个数
                if(i==find(i))
                i++;
                else
                i=fa[i];//进行跳转,忽略不再要替换的数
            }
        }
        else
        printf("%lld\n",query(r)-query(l-1));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lhm-/p/12229802.html

时间: 2024-08-30 18:12:34

题解 CF920F 【SUM and REPLACE】的相关文章

CF920F SUM and REPLACE 题解

CF920F SUM and REPLACE 线段树例题解析合集 和模板的不同之处在于修改时是改为每个数的约数个数,不难发现,当一个数x<=2时,x的约数个数与本身相等,修改多少次多不会在改变 先预处理出每个数的约数个数,用线段树维护区间最大值,若<=2,则直接结束递归 对于>2的数都要暴力修改,但由于每个数的约数个数下降很快,几次后便降到<=2,所以复杂度优秀(大约是nlogn?) 这题与CF438D The Child and Sequence(区间取模),类似,也可以维护区间

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

2014 百度之星 1003 题解 Xor Sum

Xor Sum Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助.你能证明人类的智慧么? Input 输入包含若干组测试数

[LeetCode: 题解] Combination Sum

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. Note: All numbers (including target) will

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)?

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

【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,则递归向下找到