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

Posted excellent-zzy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ GSS4 (区间开根号 + 区间查询) (线段树)相关的知识,希望对你有一定的参考价值。

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

传送门

题目大意:

对于给定的(n)个数的序列,我们定义两个操作,分别是区间开根号以及区间求和。共有(m)次查询,其中(n,mleq1e5,sum_{i=1}^na_ileq1e18)

我们会发现一个神奇的事情(然而并不神奇),就是一个数多开几次平方就变成1了,一个(1e18)以内的数,开最多6次就是1,也就是说,每一个叶子节点最多只会被更新六次,所以我们用线段树维护区间最大值和区间和,对于区间最大值为1的区间就不再做任何开方操作,对于需要开平方的区间,正常更新到叶子节点,因为最多一个节点会被更新6次,这样的话这个题就解决了。

#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
using namespace std;
inline LL read() {
    LL s = 0,w = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-')
            w = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s * w;
}
LL a[N]; 
namespace Segment{
    #define ls k<<1
    #define rs k<<1|1
    struct node{
        int l,r,v;
        LL sum,Max;
    }t[N<<2];
    void build(int k, int l, int r){
        t[k].l = l,t[k].r = r;
        if(l == r){
            t[k].Max = a[l];
            t[k].sum  = a[l];
            return ;
        }
        int mid = l+r>>1;
        build(ls,l,mid),build(rs,mid + 1,r);
        t[k].sum = t[ls].sum + t[rs].sum;
        t[k].Max = max(t[ls].Max,t[rs].Max);
    }
    void update(int k, int l, int r){
        int mid = (t[k].l + t[k].r)>>1;
        if(t[k].l == t[k].r){
            t[k].Max = sqrt(t[k].Max);
            t[k].sum = sqrt(t[k].sum);
            return ;
        }
        if(t[k].Max == 1) return ;
        if(r <= mid) update(ls,l,r);
        else if(l > mid) update(rs,l,r);
        else update(ls,l,mid),update(rs,mid + 1,r);
        t[k].sum = t[ls].sum + t[rs].sum;
        t[k].Max = max(t[ls].Max,t[rs].Max);
    }
    LL query(int k, int l, int r){
        if(t[k].l == l && t[k].r == r) return t[k].sum;
        int mid = (t[k].l+t[k].r) >> 1;
        if(r <= mid) return query(ls,l,r);
        else if(l > mid) return query(rs,l,r);
        else return query(ls,l,mid) + query(rs,mid + 1,r);
    }
}
using namespace Segment;
int n,m,cas;
int main(){
    while(scanf("%lld",&n) != EOF){
        for(int i = 1;i <= n;i++) a[i] = read();
        build(1,1,n);
        m = read();
        printf("Case #%d:
",++cas);
        for(int i = 1;i <= m;i++){
            int op = read(),l = read(),r = read();
            if(l > r) swap(l,r);
            if(op == 0) update(1,l,r);
            else if(op == 1) printf("%lld
",query(1,l,r));
        }
        puts("");
    }
    return 0;
}

以上是关于SPOJ GSS4 (区间开根号 + 区间查询) (线段树)的主要内容,如果未能解决你的问题,请参考以下文章

刷题向》关于线段树的区间开根号 BZOJ3211

HDU 4027 Can you answer these queries?

luogu P4145 上帝造题的七分钟2 / 花神游历各国 维护区间和&&区间开根号

hdu 4027 Can you answer these queries? 线段树区间开根号,区间求和

开根号 HYSBZ - 3211

bzoj3211: 花神游历各国