luogu4145 上帝造题的七分钟2 (线段树)

题意:给一个数列,维护两个操作,区间开根号、询问区间和

注意到1e12开根号六次后就变成1,而且根号1等于1

也就是说,就算我们用单点修改,只要跳过1,那么修改的次数最多也就是6n

那么维护一个区间最大值,如果最大值<=1就直接跳过这个区间,剩下的单点修改即可

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #define LL long long int
 6 using namespace std;
 7 const int maxn=100010;
 8 
 9 inline LL rd(){
10     LL x=0;char c=getchar();
11     while(c<'0'||c>'9') c=getchar();
12     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
13     return x;
14 }
15 
16 LL ma[maxn*2],sum[maxn*2],num[maxn];
17 int N,M,ch[maxn*2][2],cnt,root;
18 
19 inline void update(int p){
20     sum[p]=sum[ch[p][0]]+sum[ch[p][1]];
21     ma[p]=max(ma[ch[p][0]],ma[ch[p][1]]);
22 }
23 
24 int build(int l,int r){
25     int p=++cnt;
26     if(l==r) sum[p]=ma[p]=num[l];
27     else{
28         int m=l+r>>1;
29         ch[p][0]=build(l,m);ch[p][1]=build(m+1,r);
30         update(p);
31     }return p;
32 }
33 
34 void change(int p,int l,int r,int x,int y){
35     if(ma[p]<=1) return;
36     if(l==r) sum[p]=ma[p]=sqrt(sum[p]);
37     else{
38         int m=l+r>>1;
39         if(x<=m) change(ch[p][0],l,m,x,y);
40         if(y>m) change(ch[p][1],m+1,r,x,y);
41         update(p);
42     }
43 }
44 
45 LL query(int p,int l,int r,int x,int y){
46     if(x<=l&&r<=y) return sum[p];
47     else{
48         int m=l+r>>1;LL re=0;
49         if(x<=m) re+=query(ch[p][0],l,m,x,y);
50         if(y>m) re+=query(ch[p][1],m+1,r,x,y);
51         return re;
52     }
53 }
54 
55 int main(){
56     int i,j;
57     N=rd();for(i=1;i<=N;i++) num[i]=rd();
58     root=build(1,N);M=rd();
59     for(i=1;i<=M;i++){
60         int k=rd(),l=rd(),r=rd();if(l>r) swap(l,r);
61         if(!k) change(root,1,N,l,r);
62         else printf("%lld
",query(root,1,N,l,r));
63     }
64     
65 }
原文地址:https://www.cnblogs.com/Ressed/p/9362253.html