题解 P4145 【上帝造题的七分钟2】
分块让人快乐。
当a[i]=1时,开方便不再有意义。
加上每个数不大于le12,所以每个数至多被开方6次。
直接分块暴力,维护区间和和一个标记表示是否每个元素都为1。
如果每次区间开方只不涉及完整的块,不超过2√n个元素,直接暴力即可。
如果涉及了一些完整的块,这些块经过几次操作以后就会都变成 1,区间修改时跳过那些全为 1 的块即可。
体感一下复杂度和每个元素被开方次数有关,所以是可行的。
#define ll long long
#include<iostream>
#include<cstdio>
#define N 100005
#include<cmath>
#define B 400
using namespace std;
int bg[N],l[N],r[N],fl[N],n,m;
ll a[N],sum[N];
void Turn()
{
int u,v;scanf("%d%d",&u,&v);if(u>v) swap(u,v);
if(bg[u]==bg[v])
{
if(fl[bg[u]]) return;
for(int i=u;i<=v;++i) sum[bg[u]]-=a[i],a[i]=sqrt(a[i]),sum[bg[u]]+=a[i];
if(sum[bg[u]]==r[bg[u]]-l[bg[u]]+1) fl[bg[u]]=1;
}
else
{
for(int i=bg[u]+1;i<bg[v];++i)
{
if(fl[i]) continue;
for(int j=l[i];j<=r[i];++j) sum[i]-=a[j],a[j]=sqrt(a[j]),sum[i]+=a[j];
if(sum[i]==r[i]-l[i]+1) fl[i]=1;
}
for(int i=u;i<=r[bg[u]];++i) sum[bg[u]]-=a[i],a[i]=sqrt(a[i]),sum[bg[u]]+=a[i];
for(int i=l[bg[v]];i<=v;++i) sum[bg[v]]-=a[i],a[i]=sqrt(a[i]),sum[bg[v]]+=a[i];
if(sum[bg[u]]==r[bg[u]]-l[bg[u]]+1) fl[bg[u]]=1;
if(sum[bg[v]]==r[bg[v]]-l[bg[v]]+1) fl[bg[v]]=1;
}
}
void Ask()
{
int u,v;ll ans=0;scanf("%d%d",&u,&v);if(u>v) swap(u,v);
if(bg[u]==bg[v])
{
for(int i=u;i<=v;++i) ans+=a[i];
}
else
{
for(int i=bg[u]+1;i<bg[v];++i) ans+=sum[i];
for(int i=u;i<=r[bg[u]];++i) ans+=a[i];
for(int i=l[bg[v]];i<=v;++i) ans+=a[i];
}
printf("%lld\n",ans);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
bg[i]=i/B;
l[bg[i]]=!l[bg[i]]?i:l[bg[i]];
r[bg[i]]=i;sum[bg[i]]+=a[i];
}scanf("%d",&m);
for(int i=1;i<=m;++i)
{
int fl;scanf("%d",&fl);
if(fl) Ask();
else Turn();
}
return 0;
}