Codeforces 920F - SUM and REPLACE
题意:
给定一组长度为n的数组,有m次操作(两种不同的操作)。每次操作输入三个数 t x y,如果 t==1 ,将从 x 到 y 的每一个数都变为D(i) (D(i)为 i 的因子个数),t==2 输出从 x 到 y 的和。
思路:
线段树。此处需要一点优化。2的因子个数是2,1的因子个数是1,如果需要更新的位置 所存的数 <=2则就不需要更新了。
只需更新 >2的就行。
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=300010;
ll s[4*maxn];
ll sum[4*maxn],node[maxn],mx[4*maxn];
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void bulid(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=mx[rt]=node[l];
return ;
}
int m=(l+r)>>1;
bulid(l,m,rt<<1);
bulid(m+1,r,rt<<1|1);
pushup(rt);
}
void update(int L,int R,int l,int r,int rt)
{
if(mx[rt]<=2)
return ;
if(l==r)
{
sum[rt]=mx[rt]=s[sum[rt]];
return ;
}
int m=(l+r)>>1;
if(L<=m)
update(L,R,l,m,rt<<1);
if(m<R)
update(L,R,m+1,r,rt<<1|1);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l && r<=R)
return sum[rt];
int m=(l+r)>>1;
ll ans=0;
if(L<=m)
ans+=query(L,R,l,m,rt<<1);
if(R>m)
ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
}
int main()
{
int n,m;
for(int i=1;i<=1000000;i++)
for(int j=i;j<=1000000;j+=i)
s[j]++;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&node[i]);
bulid(1,n,1);
int t,a,b;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&t,&a,&b);
if(t==1)
update(a,b,1,n,1);
else
printf("%lld\n",query(a,b,1,n,1));
}
return 0;
}
还有一种树状数组的做法:https://blog.csdn.net/Mitsuha_/article/details/79246116