hdu 4027 Can you answer these queries? 线段树
区间开根,区间求和。
最大的int开不到10次根也会变成1。每次开根都暴力处理,最多也不过是10N的复杂度。
所以每个节点维护一个标记,子树所代表的区间是否都小于等于1,成立就不开根了,从而维护复杂度正确性。
注意输入的l和r可能先大后小,需要交换....
跟BZOJ花神游历各国是一个题。
1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 ll n,m,T; 8 ll data[500000],opt[500000],sec[100005]; 9 void build(ll k,ll l,ll r) 10 { 11 if (l == r) 12 { 13 data[k] = sec[l]; 14 if (sec[l] <= 1) 15 opt[k] = 1; 16 else 17 opt[k] = 0; 18 return; 19 } 20 ll mid = l + r >> 1; 21 build(k << 1,l,mid); 22 build(k << 1 | 1,mid + 1,r); 23 data[k] = data[k << 1] + data[k << 1 | 1]; 24 opt[k] = opt[k << 1] && opt[k << 1 | 1]; 25 } 26 ll query(ll k,ll l,ll r,ll x,ll y) 27 { 28 if (x <= l && r <= y) return data[k]; 29 ll mid = l + r >> 1,res = 0; 30 if (x <= mid) res += query(k << 1,l,mid,x,y); 31 if (y > mid) res += query(k << 1 | 1,mid + 1,r,x,y); 32 return res; 33 } 34 void change(ll k,ll l,ll r,ll x,ll y) 35 { 36 if (opt[k]) return; 37 if (l == r) 38 { 39 data[k] = sqrt(data[k]); 40 if (data[k] <= 1) opt[k] = 1; 41 return; 42 } 43 ll mid = l + r >> 1; 44 if (x <= mid) change(k << 1,l,mid,x,y); 45 if (y > mid) change(k << 1 | 1,mid + 1,r,x,y); 46 data[k] = data[k << 1] + data[k << 1 | 1]; 47 opt[k] = opt[k << 1] && opt[k << 1 | 1]; 48 } 49 int main() 50 { 51 while (scanf("%lld",&n) > 0) 52 { 53 printf("Case #%lld:\n",++T); 54 for (ll i = 1;i <= n;i++) scanf("%lld",&sec[i]); 55 build(1,1,n); 56 scanf("%lld",&m); 57 ll tx,tl,tr; 58 for (ll i = 1;i <= m;i++) 59 { 60 scanf("%lld%lld%lld",&tx,&tl,&tr); 61 if (tl > tr) 62 swap(tl,tr); 63 if (tx == 1) printf("%lld\n",query(1,1,n,tl,tr));else 64 change(1,1,n,tl,tr); 65 } 66 printf("\n"); 67 } 68 return 0; 69 }
心之所动 且就随缘去吧