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\n",query(root,1,N,l,r)); 63 } 64 65 }