SPOJ GSS4 (区间开根号 + 区间查询) (线段树)

题目

这个题目camp里面有讲过,用到的是BOZJ 3211

题意

对于给定的,n个数的序列,我们定义两个操作,分别是区间开根号以及区间求和。共有m次查询
其中 n,m1e5,ni=1ai1e18 n , m ≤ 1 e 5 , ∑ i = 1 n a i ≤ 1 e 18

思路

我们可以简单的计算一下,一个 1e18 1 e 18 以内的数,经过最多6次开平方操作后,会变成1。那么也就是说,我们如果建立了线段树,对于每一个叶子节点我们最多进行6次的更新操作后,每次就不会改变大小了。那么我们可以通过维护区间的最大值和区间和,对于区间最大值是1的区间,我们就可以直接不考虑了。因为对其中所有数做开平方操作,都不会改变区间的数,以及区间和。
那么整理思路,我们就是维护区间和及区间最大值,对于最大值等于1的区间,我们不用进行开平方操作,对于需要进行开平方的区间,我们一直更新到叶子节点,因为每个叶子节点最多更新6次,所以这个是可以接受的,时间复杂度 O(6nlogn) O ( 6 n log ⁡ n ) O(nlogn) O ( n log ⁡ n )

代码


struct Node{
    int l, r;
    ll sum, maxx;     //特征值
    int lazy;
}tree[maxn<<2];              //开四倍空间
ll num[maxn];               //数值数组

void build(int i, int l, int r){
    tree[i].l = l;
    tree[i].r = r;
    if(l == r){
        tree[i].maxx = num[l];
        tree[i].sum  = num[l];
        return ;
    }

    int mid = (l+r)>>1;
    build(i<<1, l, mid);
    build(i<<1|1, mid+1, r);

    tree[i].sum  = tree[i<<1].sum+tree[i<<1|1].sum;
    tree[i].maxx = max(tree[i<<1].maxx, tree[i<<1|1].maxx);
}

void update(int i, int l, int r){
    int mid = (tree[i].l+tree[i].r)>>1;

    if(tree[i].l == tree[i].r){
        tree[i].maxx = sqrt(tree[i].maxx);
        tree[i].sum  = sqrt(tree[i].sum);
        return ;
    }

    if(tree[i].maxx == 1)
        return ;

    if(r <= mid) update(i<<1, l, r);
    else if(l > mid) update(i<<1|1, l, r);
    else {
        update(i<<1, l, mid);
        update(i<<1|1, mid+1, r);
    }

    tree[i].sum  = tree[i<<1].sum + tree[i<<1|1].sum;
    tree[i].maxx = max(tree[i<<1].maxx, tree[i<<1|1].maxx);
}

ll query(int i, int l, int r){
    if(tree[i].l == l && tree[i].r == r)
        return  tree[i].sum;

    int mid = (tree[i].l+tree[i].r)>>1;

    if(r <= mid) return query(i<<1, l, r);
    else if(l > mid) return query(i<<1|1, l, r);
    else return query(i<<1, l, mid) + query(i<<1|1, mid+1, r);
}


int main()
{
    int n, m, cas = 1;
    while(sd(n) != EOF){

        printf("Case #%d:\n", cas++);

        rep(i, 1, n+1)
            sld(num[i]);

        build(1, 1, n);

        sd(m);
        rep(i, 0, m){
            int op, l, r;
            sddd(op, l, r);

            if(l > r) swap(l, r);

            if(op == 0) update(1, l, r);
            else if(op == 1) pld(query(1, l, r));
        }
    }

    return 0;
}

你可能感兴趣的:(数据结构)