[bzoj3038]上帝造题的7分钟2

考虑每一个位置最多开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\n",query(1,1,n,l,r));
50     }
51 }
View Code

 

posted @ 2019-11-10 08:28  PYWBKTDA  阅读(124)  评论(0编辑  收藏  举报