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: ", ++cas ); while ( Q-- ) { int op, a, b; scanf( "%d%d%d", &op, &a, &b ); if ( b < a ) swap(a, b); if ( op ) { printf("%I64d ", Query( a, b, 1, N, 1 ) ); } else { Update( a, b, 1, N, 1 ); } } puts(""); } return 0; }
原文地址:https://www.cnblogs.com/GBRgbr/p/3361653.html