zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    25、排序算法之选择法排序 (待完成)
    24、求一个3×3的整型矩阵对角线元素之和
    23、32、输入一个字符,输出其大写字符 (待完成)
    22、有一个已排好序的数组,要求输入一个数字后,按原来的排序规律将它插入数组
    21、二维数组行列转换
    20、30、用冒泡法对N个数排序--升序 (完成)
    19、求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个1~9的数字。例如2+22+222+2222+22222(此时共有5个数相加)。
    18、1-3+5-7+···-99+101等于多少
    17、反向输出
    16、判断101-200之间有多少个素数,并输出所有素数。
  • 原文地址:https://www.cnblogs.com/excellent-zzy/p/12404249.html
Copyright © 2011-2022 走看看