[线段树]关于整段修改成a[i],并查询

博客介绍了解题的主要方法,提前预留di数组并运用线段树。在解题过程中发现因子数并非i - phi[i] + 1,数据迭代最终会变成1或2。最初按线段树一般解法超时,后发现可通过定义区间最大值优化,若最大值 <= 2则不必往下放以节约时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要解法

肯定要提前预留出di 数组,然后就是线段树。

刚开始以为 因子数=i-phi[i]+1

后来发现并不是,4和6不是因子关系,但是他们不是互质的,这两个的含义不一样, 并不是互补的

我们发现数据范围为1e6,然后一步步迭代 最终都会变成 1或者 2  d[1]=1  d[2]=2;  最多可迭代6次。

刚开始按照线段树一般解法,用Update 区间修改,是这点的话,就变成d[i],不是的话,就往下放,并且要push-up

查询用long long 

后来发现超时了,我们发现不是每次都需要往下放的,就比如 d[2]=d[d[2]],就没有任何意义。

我们用一个最大值来定义区间的最大值,如果最大值<=2,那么就不必往下放,节约时间。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <set>
 7 #include <map>
 8 #include <vector>
 9 #include <cctype>
10 #include <sstream>
11 using namespace std;
12 typedef long long ll;
13 const int inf=0x7fffffff;
14 const int N=1e6+100;
15 const int M=3*1e5+100;
16 ll tree[M<<2],d[N],mx[M<<2];
17 int n,m;
18 void init()
19 {
20     for(int i=1;i<N;i++)
21         for(int j=i;j<N;j+=i)
22             d[j]++;
23     //for(int i=1;i<=10;i++)
24     //    cout<<i<<" "<<d[i]<<endl;
25 }
26 void push_up(int rt)
27 {
28     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
29     mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
30 }
31 void build(int rt,int l,int r)
32 {
33     if(l==r)
34     {
35         scanf("%lld",&tree[rt]);
36         mx[rt]=tree[rt];
37         return;
38     }
39     int m=(l+r)/2;
40     build(rt<<1,l,m);
41     build(rt<<1|1,m+1,r);
42     push_up(rt);
43 }
44 void update(int L,int R,int rt,int l,int r)
45 {
46     if(mx[rt]<=2)   return ;
47     if(l==r)
48     {
49         tree[rt]=mx[rt]=d[tree[rt]];
50         return ;
51     }
52     int m=(l+r)/2;
53     if(L<=m)    update(L,R,rt<<1,l,m);
54     if(R>m)     update(L,R,rt<<1|1,m+1,r);
55     push_up(rt);
56 }
57 ll query(int L,int R,int rt,int l,int r)
58 {
59     if(L<=l&&r<=R)  return tree[rt];
60     ll ans=0;
61     int m=(l+r)/2;
62     if(L<=m)    ans+=query(L,R,rt<<1,l,m);
63     if(R>m)     ans+=query(L,R,rt<<1|1,m+1,r);
64     return ans;
65 }
66 int main()
67 {
68     init();
69     scanf("%d %d",&n,&m);
70     build(1,1,n);
71     while(m--)
72     {
73         int k,l,r;
74         scanf("%d %d %d",&k,&l,&r);
75         if(k==1)
76             update(l,r,1,1,n);
77         else
78             cout<<query(l,r,1,1,n)<<endl;
79     }
80 
81     return 0;
82 }
View Code

解决这种题目的方法:

1.提前写出d[i]数组

2.线段树

3.看是否可以优化。

 

转载于:https://www.cnblogs.com/Kaike/p/10799960.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值