题意:在一场战役中,敌方有一排编号为1至n的战舰。你的指挥官有两种命令: 1.下令使用秘密武器攻击敌方战舰,每次攻击使得敌方一定范围的所有战舰的耐久度降低至原来的平方根(若平方根不为整数,那么舍去后面的小数部分)。2.询问敌方一定范围内的所有战舰的耐久度之和。
题解:网赛卡在这道题上了。泪流满面呀。稍不注意就TL, 超时的代码也贴出来,吸取教训···。
640ms,把down函数内联可以到500几吧。
#include <cmath> #include <iostream> using namespace std; #define lint __int64 #define L(u) (u<<1) #define R(u) (u<<1|1) #define max(a,b) (a>b?a:b) #define N 200005 lint sum[N][10]; lint array[N][10]; lint maxNum, maxSqrt; struct Node { int l, r, v, add, flag; /* flag == 1说明节点内部所有点的v值一样,即受到攻击次数一样 */ } node[N*4]; void build ( int u, int l, int r ) { node[u].l = l; node[u].r = r; node[u].v = node[u].add = 0; node[u].flag = 1; if ( l == r ) return; lint mid = ( l + r ) >> 1; build ( L(u), l, mid ); build ( R(u), mid+1, r ); } void down ( int u ) { if ( node[u].add != 0 ) { node[L(u)].v += node[u].add; node[R(u)].v += node[u].add; node[L(u)].add += node[u].add; node[R(u)].add += node[u].add; node[u].add = 0; } node[u].flag = -1; /* 每次向下更新时,因为节点内部的 v 不可能全部一样了,所以需要把 flag 置为 -1 */ } void update ( int u, int l, int r ) { if ( (l == node[u].l && node[u].r == r) || node[u].l == node[u].r ) { node[u].v++; node[u].add++; return; } down(u); int mid = ( node[u].l + node[u].r ) >> 1; if ( r <= mid ) update ( L(u), l, r ); else if ( l > mid ) update ( R(u), l, r ); else { update ( L(u), l, mid ); update ( R(u), mid+1, r ); } } lint query ( int u, int l, int r ) { if ( l == node[u].l && node[u].r == r ) { if ( node[u].v >= maxSqrt ) node[u].v = maxSqrt; if ( node[u].v == maxSqrt || node[u].l == node[u].r || node[u].flag == 1 ) return sum[r][node[u].v] - sum[l-1][node[u].v]; down(u); return query( L(u), l, (l+r)/2 ) + query( R(u), (l+r)/2+1, r ); } down(u); int mid = ( node[u].l + node[u].r ) >> 1; if ( r <= mid ) return query ( L(u), l, r ); else if ( l > mid ) return query ( R(u), l, r ); else return query ( L(u), l, mid ) + query ( R(u), mid+1, r ); } int main() { int n, m; int t, x, y, i, j; int test = 0; while ( scanf("%d",&n) != EOF ) { maxNum = 0; for ( i = 1; i <= n; i++ ) { scanf("%I64d", &array[i][0]); if ( array[i][0] > maxNum ) maxNum = array[i][0]; } maxSqrt = 0; while ( maxNum > 1 ) { maxNum = (lint) sqrt(maxNum+0.0); maxSqrt++; } for ( i = 0; i < 10; i++ ) sum[0][i] = 0; for ( i = 1; i <= n; i++ ) { for ( j = 0; j <= maxSqrt; j++ ) { if ( j == 0 ) sum[i][0] = sum[i-1][0] + array[i][0]; else { array[i][j] = (lint) sqrt(array[i][j-1]+0.0); sum[i][j] = sum[i-1][j] + array[i][j]; } } } build ( 1, 1, n ); scanf("%d",&m); printf("Case #%d:\n", ++test); while( m-- ) { scanf("%d%d%d",&t,&x,&y); if ( x > y ) swap(x,y); if ( t == 0 ) update ( 1, x, y ); else printf("%I64d\n", query ( 1, x, y )); } putchar('\n'); } return 0; }
812ms:
#include <cmath> #include <iostream> using namespace std; #define lint __int64 #define L(u) (u<<1) #define R(u) (u<<1|1) #define N 200005 lint array[N]; lint maxNum; int n, m, maxSqrt; struct Node { int l, r, v, add; lint sum[8]; } node[N*4]; void build ( int u, int l, int r ) { node[u].l = l; node[u].r = r; node[u].v = 0; node[u].add = 0; if ( l == r ) { lint temp, i = 0; node[u].sum[0] = temp = array[l]; if ( array[l] == 0 ) { for ( i = 0; i <= maxSqrt; i++ ) node[u].sum[i] = 0; return; } while ( temp > 1 ) { temp = (lint) sqrt(temp+0.0); node[u].sum[++i] = temp; } while ( i <= maxSqrt ) node[u].sum[++i] = 1; return; } int mid = ( l + r ) >> 1; build ( L(u), l, mid ); build ( R(u), mid+1, r ); for ( int i = 0; i <= maxSqrt; i++ ) node[u].sum[i] = node[L(u)].sum[i] + node[R(u)].sum[i]; } void update ( int u, int l, int r ) { if ( l == node[u].l && node[u].r == r ) { node[u].v++; node[u].add++; return; } if ( node[u].add != 0 ) { node[L(u)].v += node[u].add; node[R(u)].v += node[u].add; node[L(u)].add += node[u].add; node[R(u)].add += node[u].add; node[u].add = 0; } int mid = ( node[u].l + node[u].r ) >> 1; if ( r <= mid ) update ( L(u), l, r ); else if ( l > mid ) update ( R(u), l, r ); else { update ( L(u), l, mid ); update ( R(u), mid+1, r ); } } lint query ( int u, int l, int r ) { if ( l == node[u].l && node[u].r == r ) { if ( node[u].v > maxSqrt ) node[u].v = maxSqrt; if ( node[u].v == maxSqrt || node[u].l == node[u].r ) return node[u].sum[node[u].v]; if ( node[u].add != 0 ) { node[L(u)].v += node[u].add; node[R(u)].v += node[u].add; node[L(u)].add += node[u].add; node[R(u)].add += node[u].add; node[u].add = 0; } int mid = ( node[u].l + node[u].r ) >> 1; return query ( L(u), l, mid ) + query ( R(u), mid+1, r ); } if ( node[u].add != 0 ) { node[L(u)].v += node[u].add; node[R(u)].v += node[u].add; node[L(u)].add += node[u].add; node[R(u)].add += node[u].add; node[u].add = 0; } int mid = ( node[u].l + node[u].r ) >> 1; if ( r <= mid ) return query ( L(u), l, r ); else if ( l > mid ) return query ( R(u), l, r ); else return query ( L(u), l, mid ) + query ( R(u), mid+1, r ); } int main() { int t, x, y, test = 0; while ( scanf("%d",&n) != EOF ) { maxNum = 0; for ( int i = 1; i <= n; i++ ) { scanf("%I64d", &array[i]); maxNum = array[i] > maxNum ? array[i] : maxNum; } maxSqrt = 0; while ( maxNum > 1 ) { maxNum = (lint) sqrt(maxNum+0.0); maxSqrt++; } build ( 1, 1, n ); scanf("%d",&m); printf("Case #%d:\n", ++test); while( m-- ) { scanf("%d%d%d",&t,&x,&y); if ( x > y ) swap(x,y); if ( t == 0 ) update ( 1, x, y ); else printf("%I64d\n", query ( 1, x, y )); } putchar('\n'); } return 0; }
#include <cmath> #include <iostream> using namespace std; #define lint __int64 #define L(u) (u<<1) #define R(u) (u<<1|1) #define max(a,b) (a>b?a:b) #define N 200005 lint sum[N][10]; lint array[N][10]; lint maxNum, maxSqrt; struct Node { int l, r, v, flag; } node[N*4]; void build ( int u, int l, int r ) { node[u].l = l; node[u].r = r; node[u].v = 0; node[u].flag = 1; if ( l == r ) return; lint mid = ( l + r ) >> 1; build ( L(u), l, mid ); build ( R(u), mid+1, r ); } void down ( int u ) { if ( node[u].v != 0 ) { node[L(u)].v += node[u].v; node[R(u)].v += node[u].v; node[u].v = 0; } node[u].flag = -1; } void update ( int u, int l, int r ) { if ( (l == node[u].l && node[u].r == r) || node[u].l == node[u].r ) { node[u].v++; return; } down(u); int mid = ( node[u].l + node[u].r ) >> 1; if ( r <= mid ) update ( L(u), l, r ); else if ( l > mid ) update ( R(u), l, r ); else { update ( L(u), l, mid ); update ( R(u), mid+1, r ); } } lint query ( int u, int l, int r ) { if ( l == node[u].l && node[u].r == r ) { if ( node[u].v >= maxSqrt ) node[u].v = maxSqrt; if ( node[u].v == maxSqrt || node[u].l == node[u].r || node[u].flag == 1 ) return sum[r][node[u].v] - sum[l-1][node[u].v]; down(u); return query( L(u), l, (l+r)/2 ) + query( R(u), (l+r)/2+1, r ); } down(u); int mid = ( node[u].l + node[u].r ) >> 1; if ( r <= mid ) return query ( L(u), l, r ); else if ( l > mid ) return query ( R(u), l, r ); else return query ( L(u), l, mid ) + query ( R(u), mid+1, r ); } int main() { int n, m; int t, x, y, i, j; int test = 0; while ( scanf("%d",&n) != EOF ) { maxNum = 0; for ( i = 1; i <= n; i++ ) { scanf("%I64d", &array[i][0]); if ( array[i][0] > maxNum ) maxNum = array[i][0]; } maxSqrt = 0; while ( maxNum > 1 ) { maxNum = (lint) sqrt(maxNum+0.0); maxSqrt++; } for ( i = 0; i < 10; i++ ) sum[0][i] = 0; for ( i = 1; i <= n; i++ ) { for ( j = 0; j <= maxSqrt; j++ ) { if ( j == 0 ) sum[i][0] = sum[i-1][0] + array[i][0]; else { array[i][j] = (lint) sqrt(array[i][j-1]+0.0); sum[i][j] = sum[i-1][j] + array[i][j]; } } } build ( 1, 1, n ); scanf("%d",&m); printf("Case #%d:\n", ++test); while( m-- ) { scanf("%d%d%d",&t,&x,&y); if ( x > y ) swap(x,y); if ( t == 0 ) update ( 1, x, y ); else printf("%I64d\n", query ( 1, x, y )); } putchar('\n'); } return 0; }