題目大意:
先定義一個,現在給你一個序列,你要做兩種操作,操作替換。操作求區間所有數字和。
思路:
這題與D. The Child and Sequence是一個套路,注意到將到,不會超過次(很顯然次數特別少),所以可以可以單點修改,維護一個最大值,當最大值,這個區間可以不管了,因爲。所以粗略的估計總複雜度不會超過。
總結:有點體會到線段樹套路題了。單點修改的時候也要修改(一開始忘記了。)。
代碼:
#include<iostream>
using namespace std;
typedef long long int ll;
const int maxn = 3e5 + 10;
const int maxx = 1e6 + 10;
int ans[maxx];
struct seg{
int l,r;
ll s,m;
seg(){s = 0,m = 0;}
seg(int a,int b):l(a),r(b){}
}tree[maxn << 2];
void build(int id,int l,int r){
tree[id] = {l,r};
if(l == r){
scanf("%lld",&tree[id].s);
tree[id].m = tree[id].s;
return ;
}
int mid = l + r >> 1;
build(id << 1,l,mid);
build((id << 1) + 1,mid + 1 ,r);
tree[id].s = tree[id << 1].s + tree[(id << 1) + 1].s;
tree[id].m = max(tree[id << 1].m ,tree[(id << 1) + 1].m);
}
ll query(int id,int l,int r){
if(tree[id].l >= l && tree[id].r <= r){
return tree[id].s;
}
int mid = tree[id].l + tree[id].r >> 1;
ll ans = 0;
if(r <= mid)return ans += query(id << 1,l,r);
else if(l > mid) return ans += query((id << 1) + 1,l,r);
else return ans += query(id << 1,l,r) + query((id << 1) + 1,l,r);
}
void update(int id,int l,int r){
if(tree[id].m <= 2)return;
if(tree[id].l >= l && tree[id].r <= r && tree[id].l == tree[id].r){
tree[id].m = tree[id].s = ans[tree[id].s];
return ;
}
int mid = tree[id].l + tree[id].r >> 1;
if(r <= mid) update(id << 1,l,r);
else if(l > mid) update((id << 1) + 1,l,r);
else update(id << 1,l,r) , update((id << 1) + 1,l,r);
tree[id].s = tree[id << 1].s + tree[(id << 1) + 1].s;
tree[id].m = max(tree[id << 1].m ,tree[(id << 1) + 1].m);
}
void solved(){
for(int i = 1; i <= 1e6; i++){
for(int j = i; j <= 1e6; j += i)
ans[j]++;
}
int n,m;cin>>n>>m;
build(1,1,n);
while(m--){
int ins,l,r;scanf("%d%d%d",&ins,&l,&r);
if(ins == 2){
printf("%lld\n",query(1,l,r));
}
if(ins == 1){
update(1,l,r);
}
}
}
int main(){
solved();
return 0;
}