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; }