考虑每一个位置最多开6次左右就会变成1,然后操作就没有意义了,因此对线段树维护区间和和一个标记,表示是否全部都是1,然后对于修改,如果区间标记不是1就暴力下去,是1就不用操作,复杂度为$o(6nlogn)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define ll long long 5 #define L (k<<1) 6 #define R (L+1) 7 #define mid (l+r>>1) 8 int n,m,p,l,r,laz[N<<2]; 9 ll f[N<<2]; 10 void up(int k){ 11 laz[k]=(laz[L]&laz[R]); 12 f[k]=f[L]+f[R]; 13 } 14 void build(int k,int l,int r){ 15 if (l==r){ 16 scanf("%lld",&f[k]); 17 if (f[k]==1)laz[k]=1; 18 return; 19 } 20 build(L,l,mid); 21 build(R,mid+1,r); 22 up(k); 23 } 24 void update(int k,int l,int r,int x,int y){ 25 if ((l>y)||(x>r))return; 26 if ((x<=l)&&(r<=y)&&(laz[k]))return; 27 if (l==r){ 28 f[k]=(ll)sqrt(f[k]); 29 if (f[k]==1)laz[k]=1; 30 return; 31 } 32 update(L,l,mid,x,y); 33 update(R,mid+1,r,x,y); 34 up(k); 35 } 36 ll query(int k,int l,int r,int x,int y){ 37 if ((l>y)||(x>r))return 0; 38 if ((x<=l)&&(r<=y))return f[k]; 39 return query(L,l,mid,x,y)+query(R,mid+1,r,x,y); 40 } 41 int main(){ 42 scanf("%d",&n); 43 build(1,1,n); 44 scanf("%d",&m); 45 for(int i=1;i<=m;i++){ 46 scanf("%d%d%d",&p,&l,&r); 47 if (l>r)swap(l,r); 48 if (!p)update(1,1,n,l,r); 49 else printf("%lld ",query(1,1,n,l,r)); 50 } 51 }