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, $ 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:
 
$ 1. REPLACE \quad l \quad r $ —— for every $ i \in [l,r] $ replace $ a_i $ with $ D(a_i) $ ;
$ 2. SUM \quad l \quad r $ —— calculate $ \sum_{i=l}^r a_i $ .
 
Print the answer for each $ SUM $ query.
 

Input

The first line contains two integers $ n $ and $ m (1?≤?n,?m?≤?3·10^5) $
— the number of elements in the array and the number of queries to process, respectively.
 
The second line contains n integers $ a_1, a_2, ..., a_n (1?≤?ai?≤?10^6) $ — the elements of the array.
 
Then $ m $ lines follow, each containing $ 3 $ integers $ t_i, l_i, r_i $ denoting $ i $ -th query.
If $ ti?=?1 $ , then $ i $ -th query is $ REPLACE \quad l_i \quad r_i $ , otherwise it‘s $ SUM \quad l_i \quad r_i (1?≤?t_i?≤?2, 1?≤?l_i?≤?r_i?≤?n) $ .
 
There is at least one $ SUM $ query.
 

Output

For each $ SUM $ query print the answer to it.
 

Examples

input

 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

output

 30
 13
 4
 22

 

题目大意

  • 给你 $ n $ 个数,进行 $ m $ 次操作,分别是将区间 $ [l,r] $ 内的所有数替换成自己的因子数 和 对区间 $ [l,r] $ 进行求和。
  • 数据范围: $ 1 \le n,m \le 3 \times 10^5 $
     

思路

  • 首先可以用线段树来维护序列,每次暴力修改。
    因为 $ D(1)=1, D(2)=2 $,因此当一个区间的最大值小于2时就不需要修改。
     
  • 又因为每次修改只会让值减少,而且每个数最多会被修改 $ O(logn) $ 次,因此能够保证复杂度
     

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXM 1000005
#define N 300005
#define int long long
int n,m,M;
int d[MAXM],c[MAXM],p[MAXM];
bool vis[MAXM];
void pre(){
    d[1]=1;
    for(int i=2;i<=M;++i){
        if(!vis[i]){ p[++p[0]]=i; vis[i]=1; d[i]=2; c[i]=1; }
        for(int j=1;j<=p[0]&&1ll*i*p[j]<=M;++j){
            vis[i*p[j]]=1;
            if(i%p[j]==0){
                d[i*p[j]]=d[i]/(c[i]+1)*(c[i]+2);
                c[i*p[j]]=c[i]+1;
                break;
            }
            d[i*p[j]]=d[i]*2;
            c[i*p[j]]=1;
        }
    }
}
int sum[N<<2];
bool flag[N<<2];
void build(int o,int l,int r){
    if(l==r){
        scanf("%lld",&sum[o]);
        if(sum[o]==1||sum[o]==2) flag[o]=1;
        M=max(M,sum[o]);
        return;
    }
    int mid=l+r>>1;
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    sum[o]=sum[o<<1]+sum[o<<1|1];
    flag[o]=flag[o<<1]&flag[o<<1|1];
}
void updata(int o,int l,int r,int L,int R){
    if(flag[o]) return;
    if(l==r&&L<=l&&l<=R){
        sum[o]=d[sum[o]];
        if(sum[o]==1||sum[o]==2) flag[o]=1;
        return;
    }
    int mid=l+r>>1;
    if(L>mid) updata(o<<1|1,mid+1,r,L,R);
    else if(R<=mid) updata(o<<1,l,mid,L,R);
    else {
        updata(o<<1,l,mid,L,R);
        updata(o<<1|1,mid+1,r,L,R);
    }
    sum[o]=sum[o<<1]+sum[o<<1|1];
    flag[o]=flag[o<<1]&flag[o<<1|1];
}
int query(int o,int l,int r,int L,int R){
    if(L<=l&&r<=R) return sum[o];
    int mid=l+r>>1;
    if(L>mid) return query(o<<1|1,mid+1,r,L,R);
    else if(R<=mid) return query(o<<1,l,mid,L,R);
    else return query(o<<1,l,mid,L,R)+query(o<<1|1,mid+1,r,L,R);
}
signed main(){
    scanf("%lld %lld",&n,&m);
    build(1,1,n);
    pre();
    while(m--){
        int opt,x,y;
        scanf("%lld %lld %lld",&opt,&x,&y);
        if(opt==1) updata(1,1,n,x,y);
        else printf("%lld\n",query(1,1,n,x,y));
    }
    return 0;
}
/*
#          42607112
When       2018-09-07 11:38:57
Who        PotremZ
Problem    F - SUM and REPLACE
Lang       GNU C++11
Verdict    Accepted
Time       467 ms
Memory     35000 KB
*/

原文地址:https://www.cnblogs.com/PotremZ/p/9606942.html

时间: 2024-10-09 11:09:39

codeforces CF920F 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

Codeforces 85D Sum of Medians(线段树)

85D Sum of Medians 题目链接 题意:一个集合有添加,删除元素,每次查询输出集合位置为i % 5 == 3的位置和 思路:线段树,线段树记录下% 5 == 0, 1, 2, 3, 4的和,并且记录一个mov表示右移多少,每次添加一个值的时候,就当前位置之后的一整段位置都要右移一个单位,这样去搞线段树维护一下即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <

POJ - 2886线段树+线性筛

题意就是给你n个人,每个人有一个名字和A,如果A为正则向左找第A个,否则向右找第-A个,每找到一个就出列,然后第i个人出列的F(i)是i的所有因子个数 输出最大的F(i)和对应的名字 先用线性筛找出第几个出列的值最大maxn,那么求到maxn就可以了. 用线段树记录空位,k表示当前需要从剩余人第几个位置寻找,只要推出k,则转化为线段树的求位置的模型 #include<iostream> #include<cstdio> #include<cstring> using n

CF920F SUM and REPLACE 题解

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

Codeforces 444C DZY Loves Colors(线段树)

题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是修改区间上l到r上面德值为x,2是询问l到r区间总的修改值. 解题思路:线段树模板题. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 5*1e5; typedef long lo

Codeforces 57B Martian Architecture 暴力||线段树

题目链接:点击打开链接 题意:n长的序列(初始全为0) m个操作 k个查询 下面m个操作[l,r] h 代表 a[l] +=h; a[l+1] += h+i; a[l+i] += h+i;  l<=i<=r 然后问k个位置的和 因为k<=100 所以直接暴力也可以 ----------------------- 如果k<=100000 也是可以做的 只需要给区间记录一个标记lazy,表示从左端点开始 l, l+1, l+i ··· l+r 而向下更新时, 左区间则直接更新, 右区间

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

Educational Codeforces Round 72 (Rated for Div. 2)E. Sum Queries?(线段树区间合并)

https://codeforc.es/contest/1217/problem/E 建立9棵数位线段树维护区间最小值和次小值,建议用struct建树方便进行区间合并 1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #define IO std::ios::sync_with_stdio(0) 3 #include <bits/stdc++.h> 4 #define iter ::it

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing