题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3211
题解:
线段树区间开根号操作,目前只能通过单点修改来实现,但是发现:一个小于109的数开过5次根号后向下取整就会变成1
所以在每一次开根号操作后判断,如果这个数已经开到1甚至0,则线段树当前结点flag值设为true,以后再访问该结点时不再操作
父结点的flag值可以由两个儿子的flag值按位与得到
只有开根号操作的话代码还是比较简单的
1 #include<cstdio> 2 #include<cmath> 3 #define MAXN 400010 4 #define LL long long 5 LL sumv[MAXN],flag[MAXN]; 6 int n,m,t1,yl,yr; 7 void build(int o,int L,int R) 8 { 9 int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2; 10 if(L==R) 11 { 12 scanf("%lld",&sumv[o]); 13 return; 14 } 15 build(lc,L,M); 16 build(rc,M+1,R); 17 sumv[o]=sumv[lc]+sumv[rc]; 18 flag[o]=flag[lc]&flag[rc]; 19 } 20 void update(int o,int L,int R) 21 { 22 if(flag[o])return; 23 int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2; 24 if(L==R) 25 { 26 sumv[o]=sqrt(sumv[o]); 27 if(!sumv[o]||sumv[o]==1)flag[o]=true; 28 return; 29 } 30 if(yl<=M)update(lc,L,M); 31 if(yr>M)update(rc,M+1,R); 32 sumv[o]=sumv[lc]+sumv[rc]; 33 flag[o]=flag[lc]&flag[rc]; 34 } 35 LL query(int o,int L,int R) 36 { 37 int lc=o<<1,rc=(o<<1)+1,M=(L+R)>>1; 38 if(yl<=L&&yr>=R)return sumv[o]; 39 LL ans=0; 40 if(yl<=M)ans=query(lc,L,M); 41 if(yr>M)ans+=query(rc,M+1,R); 42 sumv[o]=sumv[lc]+sumv[rc]; 43 return ans; 44 } 45 int main() 46 { 47 scanf("%d",&n); 48 build(1,1,n); 49 scanf("%d",&m); 50 while(m--) 51 { 52 scanf("%d%d%d",&t1,&yl,&yr); 53 if(t1==2)update(1,1,n); 54 else printf("%lld\n",query(1,1,n)); 55 } 56 return 0; 57 }
原文:http://www.cnblogs.com/xqmmcqs/p/5971529.html