好吧,楼下有分块的解法,那么我就再阐述一遍好了
本以为暴力分块为\(TLE\)的,结果发现吊打线段树,用奇技淫巧的卡常技术卡到第一页
其实这道题就是数列分块入门\(5\)嘛,发现一个数只能被不超过\(6\)次开方,那么暴力修改,用一个标记看看整块是否有大于\(1\)的数
那么我就献上一个未卡常的分块解法
\(Code\ Below:\)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100000+10;
ll n,m,a[maxn],sum[330],v[330],pos[maxn],blo;
void change(ll x){
if(!v[x]){
v[x]=1;sum[x]=0;
for(ll i=(x-1)*blo+1;i<=x*blo;i++){
a[i]=sqrt(a[i]);
sum[x]+=a[i];
if(a[i]>1) v[x]=0;
}
}
}
void update(ll l,ll r){
if(!v[pos[l]]){
for(ll i=l;i<=min(pos[l]*blo,r);i++){
sum[pos[i]]-=a[i];
a[i]=sqrt(a[i]);
sum[pos[i]]+=a[i];
}
v[pos[l]]=1;
for(ll i=(pos[l]-1)*blo+1;i<=min(pos[l]*blo,n);i++){
if(a[i]>1){v[pos[l]]=0;break;}
}
}
if(pos[l]!=pos[r]){
if(!v[pos[r]]){
for(ll i=(pos[r]-1)*blo+1;i<=r;i++){
sum[pos[i]]-=a[i];
a[i]=sqrt(a[i]);
sum[pos[i]]+=a[i];
}
v[pos[r]]=1;
for(ll i=(pos[r]-1)*blo+1;i<=min(pos[r]*blo,n);i++){
if(a[i]>1){v[pos[r]]=0;break;}
}
}
}
for(ll i=pos[l]+1;i<=pos[r]-1;i++) change(i);
}
ll query(ll l,ll r){
ll ans=0;
for(ll i=l;i<=min(pos[l]*blo,r);i++) ans+=a[i];
if(pos[l]!=pos[r])
for(ll i=(pos[r]-1)*blo+1;i<=r;i++) ans+=a[i];
for(ll i=pos[l]+1;i<=pos[r]-1;i++) ans+=sum[i];
return ans;
}
int main()
{
scanf("%lld",&n);blo=sqrt(n);
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
pos[i]=(i-1)/blo+1;
sum[pos[i]]+=a[i];
}
scanf("%lld",&m);
ll opt,l,r;
while(m--){
scanf("%lld%lld%lld",&opt,&l,&r);
if(l>r) swap(l,r);
if(opt==0) update(l,r);
else printf("%lld\n",query(l,r));
}
return 0;
}
原文地址:https://www.cnblogs.com/owencodeisking/p/9736440.html
时间: 2024-11-09 09:55:48