题目链接:
https://cn.vjudge.net/problem/HDU-4027
思路:
本题需要对区间内每个数开平方根,如果每次对区域内每个数进行处理,显然会TLE。
但是开平方有个特点,每个数开平方的次数不会太多,直到1之后每次开平方就是不变的了。
利用这一个特点,可以在线段树上作一些标记,判断子树是不是全为1或者0。
还有一个要注意的地方就是初始化线段树不能每次都从根开始,会TLE。以递归的形式直接处理输入。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 7 typedef long long ll; 8 const int maxn=100000; 9 const int maxsize=4*maxn; 10 11 struct Node 12 { 13 ll sum; 14 int tag; 15 }; 16 17 Node data[maxsize]; 18 19 void update(int a,int b,int k,int l,int r) 20 { 21 if(b<=l||a>=r) 22 return; 23 if(data[k].tag==1) 24 return; 25 if(r-l==1) 26 { 27 data[k].sum=sqrt(data[k].sum); 28 if(data[k].sum==1) 29 data[k].tag=1; 30 return; 31 } 32 int lc=2*k+1,rc=2*k+2; 33 34 update(a,b,lc,l,(l+r)/2); 35 update(a,b,rc,(l+r)/2,r); 36 37 if(data[lc].tag&&data[rc].tag) 38 data[k].tag=1; 39 data[k].sum=data[lc].sum+data[rc].sum; 40 41 } 42 43 ll query(int a,int b,int k,int l,int r) 44 { 45 if(b<=l||a>=r) 46 return 0; 47 if(a<=l&&b>=r) 48 return data[k].sum; 49 return query(a,b,2*k+1,l,(l+r)/2)+query(a,b,2*k+2,(l+r)/2,r); 50 } 51 52 void init(int k,int l,int r) 53 { 54 if(r-l==1) 55 { 56 scanf("%lld",&data[k].sum); 57 if(data[k].sum==1||data[k].sum==0) 58 data[k].tag=1; 59 return; 60 } 61 int lc=2*k+1,rc=2*k+2; 62 init(2*k+1,l,(l+r)/2); 63 init(2*k+2,(l+r)/2,r); 64 if(data[lc].tag&&data[rc].tag) 65 data[k].tag=1; 66 data[k].sum=data[lc].sum+data[rc].sum; 67 } 68 69 int main() 70 { 71 int n,v,q,a,b,k=0; 72 while(~scanf("%d",&n)) 73 { 74 memset(data,0,sizeof(Node)*4*n); 75 init(0,0,n); 76 77 scanf("%d",&q); 78 79 printf("Case #%d:\n",++k); 80 81 while(q--) 82 { 83 scanf("%d%d%d",&v,&a,&b); 84 if(a>b) 85 swap(a,b); 86 if(v==0) 87 update(a-1,b,0,0,n); 88 else 89 printf("%lld\n",query(a-1,b,0,0,n)); 90 } 91 putchar('\n'); 92 } 93 return 0; 94 }