hdu 4027 线段树 + 减少重复计算

来源:互联网 发布:淘宝发布完宝贝就下架 编辑:程序博客网 时间:2024/06/06 15:40

因为每个最多只会被更新8次左右,所以经常会出现区间的值不需要更新,所以在更新区间值的时候判断这个区间需不需要更新

如果需要了,再分下去,具体更新其实是单点更新的。

好题

/*开方的次数最多是8次  所以很容易出现一个区间内全是1的情况,这样的话如果碰到全是1的区间就不用更新了  还有得注意一个小trick,就是左边可能会大于右边233  其实还是为了减少重复运算  因为我们是一个数一个数更新,更新的时间是LOGN,而每个数最多更新8次,所以更新时间是N*8*LOGN  每次找到对应   其实算是一个单点修改的问题了……   */#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll maxn = 100005;ll N,M,T,X,Y;ll e[4*maxn];ll n;ll sumv[4 * maxn];void build(){for(n = 1; n < N; n = n * 2);for(int i = 1; i <= 2*n - 1; i++){    sumv[i] = 0;    }        for(int i = 1; i <= N; i++){    sumv[n - 1 + i] = e[i]; }for(int i = n - 1; i >= 1; i--){sumv[i]  = sumv[i * 2] + sumv[i * 2 + 1];}}ll y3,y2;void update(ll o,ll L,ll R){if (L == R && L >= y3 && L <= y2) {//如果只有一个点 ,肯定要更新 sumv[o] = sqrt(1.0*sumv[o]);return;}    else if (L >= y3 && R <= y2 && sumv[o] == (R - L + 1)) return;//如果是在更新区间内了并且已经不用更新 else{//要更新,或者是没找到更新区间,分下去找区间 ll M = L + (R - L)/2;if (y3 <= M ) update(o * 2,L,M);if (y2 > M ) update(o * 2 + 1,M + 1,R);sumv[o] = sumv[o * 2] + sumv[o * 2 + 1];}}ll query(ll o, ll L, ll R){    ll sum = 0;if (L >= y3 && R <= y2) return sumv[o];else{ll M = L + (R - L)/2;if (y3 <= M) sum += query(o*2,L, M);if (y2 > M) sum+= query(o * 2 + 1,M + 1,R); }return sum;}int main(){int cnt = 0;while(scanf("%d",&N) != EOF){cnt++;printf("Case #%d:\n",cnt);for(int i = 1; i <= N; i++){scanf("%lld",&e[i]);}build();scanf("%d",&M);//for(int i = 1; i <= 2*n - 1; i++) printf("%d ",sumv[i]);for(int i = 1; i <= M; i++){scanf("%d %d %d",&T,&y3,&y2);if (y3 > y2){int t = y2;y2 = y3;y3 = t;}if (T == 0){update(1,1,n);}else{printf("%lld\n",query(1,1,n));}}printf("\n");}return 0;}

0 0