#树状数组,并查集#CF920F SUM and REPLACE

题目


分析

由于(a_i=1或2)(d(a_i)=a_i),且其余情况修改后答案只会越来越小,
考虑用树状数组维护区间和,用并查集跳过(a_i=1或2)的情况


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1000011,M=300011;
typedef long long lll;
int n,m,a[M],f[M],Cnt; lll c[M];
int prime[M],d[N],mc[N]; bool v[N];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void print(lll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void Pro(int n){
	d[1]=1,mc[1]=1;
	for (rr int i=2;i<=n;++i){
		if (!v[i]) prime[++Cnt]=i,d[i]=mc[i]=2;
		for (rr int j=1;j<=Cnt&&prime[j]<=n/i;++j){
			v[i*prime[j]]=1;
			if (i%prime[j]==0){
				mc[i*prime[j]]=mc[i]+1;
				d[i*prime[j]]=d[i]/mc[i]*(mc[i]+1);
			    break;
			}
			mc[i*prime[j]]=2,
			d[i*prime[j]]=d[i]<<1;
		}
	}
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]); }
inline void update(int x,int y){for (;x<=n;x+=-x&x) c[x]+=y;}
inline lll query(int l,int r){
	rr lll ans=0; --l;
	for (;r>l;r-=-r&r) ans+=c[r];
	for (;l>r;l-=-l&l) ans-=c[l];
	return ans;
}
signed main(){
	n=iut(),m=iut(),Pro(N-11),f[n+1]=n+1;
	for (rr int i=1;i<=n;++i) c[i]=c[i-1]+(a[i]=iut());
	for (rr int i=n;i;--i) f[i]=i,c[i]-=c[i&(i-1)];
	for (rr int z,l,r;m;--m){
	    z=iut(),l=iut(),r=iut();
	    if (z==2) print(query(l,r)),putchar(10);
	    else for (rr int i=getf(l);i<=r;){
			update(i,d[a[i]]-a[i]),a[i]=d[a[i]];
			f[i]=i+(a[i]<3),i=(getf(i)==i)?i+1:f[i];
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13530173.html