題意:在一場戰役中,敵方有一排編號為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 200005lint 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 200005lint 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;}
TL代碼。與上面的代碼相比,僅僅是節點內少了一個add變數。但是這樣一來,每次向下更新時會把 v 置為 0, 那麼 node[u].v > maxSqrt這個最佳化條件就被減弱了。悲劇由此產生,唉··
#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 200005lint 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;}