这个题就是进行2种操作,
1、是对一个区间所有的数开平方,
2、求某个区间的和
思路:
用线段树进行更新区间,我们不难发现一个数经过一些次开方操作后总会变成1,而当一个数已经变成1以后我们便不用再对它进行开方操作,所以在更新区间的时候记录已经全部开方为1的区间,然后下次操作的时候则忽略,剩下的就是基本的线段树操作了,比较简单
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> using namespace std; const int maxn=1e5+100; int n,m; long long t[maxn*3],a[maxn]; void Build(int l,int r,int index) { if(l==r) { t[index]=a[l]; return; } int mid=(l+r)>>1; Build(l,mid,index<<1); Build(mid+1,r,index<<1|1); t[index]=t[index<<1]+t[index<<1|1]; } void Update(int L,int R,int l,int r,int index) { if(t[index]==R-L+1) return; if(L==R) { t[index]=sqrt((double)t[index]); return; } int mid=(L+R)>>1; if(r<=mid) Update(L,mid,l,r,index<<1); else if(l>mid) Update(mid+1,R,l,r,index<<1|1); else { Update(L,mid,l,mid,index<<1); Update(mid+1,R,mid+1,r,index<<1|1); } t[index]=t[index<<1]+t[index<<1|1]; } long long Query(int L,int R,int l,int r,int index) { if(l==L&&r==R) return t[index]; int mid=(L+R)>>1; if(r<=mid) return Query(L,mid,l,r,index<<1); if(l>mid) return Query(mid+1,R,l,r,index<<1|1); return Query(L,mid,l,mid,index<<1)+Query(mid+1,R,mid+1,r,index<<1|1); } int main() { int cas=1; while(scanf("%d",&n)!=EOF) { printf("Case #%d:\n",cas++); for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); Build(1,n,1); scanf("%d",&m); while(m--) { int op,l,r; scanf("%d%d%d",&op,&l,&r); if(l>r) swap(l,r); if(op==0) Update(1,n,l,r,1); else printf("%I64d\n",Query(1,n,l,r,1)); } printf("\n"); } return 0; }