HDU 4027 Can you answer these queries(线段树 + 观察 )

这题主要考察观察能力。

2^63最多只需要开7次根号就会变成1,当数字变成1之后就不需要再对其进行操作。

对于含有大于1数字的区间,向下更新。

对于数字全为1的区间,直接返回。

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <algorithm>

#include <cmath>



#define LL long long int

#define lson l, m, rt << 1

#define rson m + 1, r, rt << 1 | 1

#define lc rt << 1

#define rc rt << 1 | 1



using namespace std;



const int MAXN = 100100;



LL sum[MAXN << 2];

bool one[MAXN << 2];



void PushUp( int rt )

{

    sum[rt] = sum[lc] + sum[rc];

    one[rt] = one[lc] && one[rc];

    return;

}



void build( int l, int r, int rt )

{

    if ( l == r )

    {

        scanf( "%I64d", &sum[rt] );

        if ( sum[rt] <= 1 ) one[rt] = true;

        else one[rt] = false;

        return;

    }

    int m = ( l + r ) >> 1;

    build(lson);

    build(rson);

    PushUp( rt );

    return;

}



void Update( int L, int R, int l, int r, int rt )

{

    if ( one[rt] ) return;

    if ( l == r )

    {

        sum[rt] = (LL)sqrt( (double)sum[rt] );

        //之前这里忘了更新one,一直TLE
     if ( sum[rt] <= 1 ) one[rt] = true; else one[rt] = false; return; } int m = ( l + r ) >> 1; if ( L <= m ) Update( L, R, lson ); if ( R > m ) Update( L, R, rson ); PushUp( rt ); return; } LL Query( int L, int R, int l, int r, int rt ) {
   //这句不要,之前想错了
   //if ( one[rt] ) return (LL)r - l + 1;
if ( L <= l && r <= R ) return sum[rt]; int m = ( l + r ) >> 1; LL res = 0; if ( L <= m ) res += Query( L, R, lson ); if ( R > m ) res += Query( L, R, rson ); return res; } int N; int main() { int cas = 0; while ( scanf( "%d", &N ) == 1 ) { build( 1, N, 1 ); int Q; scanf( "%d", &Q ); printf( "Case #%d:\n", ++cas ); while ( Q-- ) { int op, a, b; scanf( "%d%d%d", &op, &a, &b ); if ( b < a ) swap(a, b); if ( op ) { printf("%I64d\n", Query( a, b, 1, N, 1 ) ); } else { Update( a, b, 1, N, 1 ); } } puts(""); } return 0; }

 

你可能感兴趣的:(HDU)