bzoj 3211 线段树
开方操作最多进行5次就可以把出现的任何数变成1.
所以用线段树暴力修改,以后修改时只需看一下是否当前区间都是0或1,如果是那么就直接返回.
1 /************************************************************** 2 Problem: 3211 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:1976 ms 7 Memory:7068 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cmath> 12 #define N 100010 13 14 typedef long long dnt; 15 struct Node { 16 dnt s; 17 bool t; 18 Node *ls, *rs; 19 }pool[N*3], *tail=pool, *root; 20 21 int n, m; 22 int aa[N]; 23 24 Node *build( int lf, int rg ) { 25 Node *nd = ++tail; 26 if( lf==rg ) { 27 nd->s = aa[lf]; 28 nd->t = aa[lf]<=1; 29 return nd; 30 } 31 int mid=(lf+rg)>>1; 32 nd->ls = build( lf, mid ); 33 nd->rs = build( mid+1, rg ); 34 nd->s = nd->ls->s + nd->rs->s; 35 nd->t = nd->ls->t && nd->rs->t; 36 return nd; 37 } 38 void modify( Node *nd, int lf, int rg, int L, int R ) { 39 if( lf==rg ) { 40 nd->s = (dnt)sqrt(nd->s); 41 nd->t = nd->s<=1; 42 return; 43 } 44 if( nd->t ) return; 45 int mid=(lf+rg)>>1; 46 if( L<=mid ) modify( nd->ls, lf, mid, L, R ); 47 if( R>mid ) modify( nd->rs, mid+1, rg, L, R ); 48 nd->s = nd->ls->s + nd->rs->s; 49 nd->t = nd->ls->t && nd->rs->t; 50 } 51 dnt query( Node *nd, int lf, int rg, int L, int R ) { 52 if( L<=lf && rg<=R ) return nd->s; 53 int mid=(lf+rg)>>1; 54 dnt rt = 0; 55 if( L<=mid ) rt+=query( nd->ls, lf, mid, L, R ); 56 if( R>mid ) rt+=query( nd->rs, mid+1, rg, L, R ); 57 return rt; 58 } 59 60 int main() { 61 scanf( "%d", &n ); 62 for( int i=1; i<=n; i++ ) 63 scanf( "%d", aa+i ); 64 root = build( 1, n ); 65 scanf( "%d", &m ); 66 for( int i=1,opt,l,r; i<=m; i++ ) { 67 scanf( "%d%d%d", &opt, &l, &r ); 68 if( opt==1 ) 69 printf( "%lld\n", query(root,1,n,l,r) ); 70 else 71 modify(root,1,n,l,r); 72 } 73 }