Tunnel Warfare(线段树 开方修改+剪枝优化

题意:

给定区间 ,有操作:

   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:\n",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\n",ans);
           }
        }
        printf("\n");
     }
     return 0;
}
posted @ 2019-03-28 18:03  易如鱼  阅读(231)  评论(0编辑  收藏  举报