题意:
给定区间 ,有操作:
0: 对指定区间内元素进行开方
1: 查询指定区间内元素和
一直tle...
因为那个开方操作每次都递归到叶子节点进行了,实际并不需要
增加数学敏感: 开方操作:同指数操作的快速增加一样,开方操作可以使一个数快速减小到1(取整条件下
因此这道题节点的更新可以进行剪枝优化: 若该节点下的所有 叶子节点已经减小到一(这是很快的),则直接return
此外,注意此题的对区间操作的l ,r 并没有说明r>l,因此输入后要判断一下
#include <bits/stdc++.h> using namespace std ; #define ll long long ll t[800050]; ll ans; void push_up( int pos){ t[pos] = t[pos<<1] + t[pos<<1|1]; } void build( int L ,int R ,int pos){ if( L==R ){scanf("%lld",&t[pos]); return;} int mid=(L +R)>>1; build(L ,mid ,pos<<1); build(mid+1 ,R ,pos<<1|1); push_up(pos); return ; } void updata( int l ,int r ,int L ,int R ,int pos){ if( t[pos]==R -L +1)return; //剪枝,该区间内所有元素已速减到1 if( L>=l && R<=r && L==R){ t[pos]=(ll) sqrt(t[pos]); return; } if(L==R)return; int mid=(L+R)>>1; if( mid >= l) updata(l ,r, L ,mid ,pos<<1); if( mid < r) updata(l ,r ,mid+1, R ,pos<<1|1); push_up(pos); return ; } void query( int l ,int r ,int L ,int R ,int pos ){ if( L >=l && R <=r){ ans+=t[pos]; return ; } if( L==R )return ; int mid=(L+R)>>1; if( mid >= l) query(l ,r, L ,mid ,pos<<1); if( mid < r) query(l ,r ,mid+1, R ,pos<<1|1); return; } int main( ){ int m,n,ks=1; while(scanf("%d",&n)!=EOF){ build( 1 , n ,1); scanf("%d" ,&m); printf("Case #%d: ",ks++); while( m--){ int t,l,r; scanf("%d%d%d",&t,&l,&r); if( l >r)swap(l,r); //判断调整l,r大小 if( t==0) updata( l ,r,1 ,n ,1); if( t==1){ ans=0; query( l, r ,1 ,n ,1); printf("%lld ",ans); } } printf(" "); } return 0; }