<题目链接>
题目大意:
给你一个序列,有两个操作,一个是求区间 l - r 的和,另一个是对区间l-r的元素修改值,x=d(x),d(x)为x的因子个数。
解题分析:
因为可能有多次修改操作,并且修改的范围可能比较大,所以提前将1~1e6范围内的数的因子个数全部打表进行处理。但是仅仅这样还是不行的,因为如果每次区间更新都暴力更新到叶子节点的话,区间更新 $O(nlog(n))$ ,然后m次询问,时间复杂度就达到了$O(n*mlog(n))$,而本题n给到了3e5,毫无疑问这样暴力更新是会超时的。我们发现1、2的因子数为它们本身,所以在更新的过程中,如果该区间都为1或2,就不用继续向下进行更新。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N int(3e5+7) 5 #define Max int(1e6+7) 6 #define lson rt<<1,l,mid 7 #define rson rt<<1|1,mid+1,r 8 #define clr(a,b) memset(a,b,sizeof(a)) 9 #define rep(i,s,t) for(int i=s;i<=t;i++) 10 typedef long long ll; 11 int n,q; 12 int arr[N],facnum[Max+100]; 13 ll flag[N<<2],tr[N<<2]; 14 15 template<typename T> 16 inline T read(T&x){ 17 x=0;int f=0;char ch=getchar(); 18 while(ch<'0'||ch>'9')f|=(ch=='-'),ch=getchar(); 19 while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar(); 20 return x=f?-x:x; 21 } 22 int Getfac(int x){ //得到该数的所有因子数 23 int sum=1,cnt; 24 for(int i=2;i*i<=x;i++){ 25 cnt=0; 26 while(x%i==0)x/=i,cnt++; 27 sum*=(cnt+1); 28 } 29 if(x>1) sum*=2; 30 return sum; 31 } 32 void Pushup(int rt){ 33 tr[rt]=tr[rt<<1]+tr[rt<<1|1]; 34 if(!flag[rt<<1]&&!flag[rt<<1|1])flag[rt]=0; //如果两个子区间都不需要修改,说明这个区间不需要再进行修改 35 } 36 void build(int rt,int l,int r){ 37 flag[rt]=1; 38 if(l==r){ 39 tr[rt]=arr[l];return; 40 } 41 int mid=(l+r)>>1; 42 build(lson);build(rson); 43 Pushup(rt); 44 } 45 void update(int rt,int l,int r,int L,int R){ //区间更新,维护一个区间标记,记录该区间是否需要改变 46 if(L<=l&&r<=R&&!flag[rt])return; //如果这部分区间不需要修改,直接返回 47 if(l==r){ 48 tr[rt]=facnum[tr[rt]]; //进行单点修改 49 if(tr[rt]==1||tr[rt]==2)flag[rt]=0; //如果该点为1或2,那么该点就不用再修改了,因为1、2的因子个数仍然为1、2 50 return; 51 } 52 int mid=(l+r)>>1; 53 if(L<=mid&&flag[rt<<1])update(lson,L,R); 54 if(R>mid&&flag[rt<<1|1])update(rson,L,R); 55 Pushup(rt); 56 } 57 ll query(int rt,int l,int r,int L,int R){ //区间查询 58 if(L<=l&&r<=R)return tr[rt]; 59 ll ans=0; 60 int mid=(l+r)>>1; 61 if(L<=mid)ans+=query(lson,L,R); 62 if(R>mid)ans+=query(rson,L,R); 63 return ans; 64 } 65 int main(){ 66 for(int i=1;i<=Max;i++)facnum[i]=Getfac(i); //打表预处理得到1~1e6中所有的数的因子个数 67 read(n);read(q); 68 rep(i,1,n)read(arr[i]); 69 build(1,1,n); 70 while(q--){ 71 int op,x,y; 72 read(op);read(x);read(y); 73 if(op==1)update(1,1,n,x,y); 74 else printf("%lld ",query(1,1,n,x,y)); 75 } 76 }
2019-02-16