spoj 2713 线段树

给定一个序列,有两种操作:对一个区间内的数字开方和求区间内所有数字的和。注意到一个即使很大的数经过没几次开方操作以后就会变成1,而1开方还是1。所以可以用线段树来维护,对于那些全部都是1的区间(即区间和等于区间长度)我们不用更新,剩下的就是区间求和了。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <cmath>
  5 using namespace std;
  6
  7 typedef long long ll;
  8 const int N = 100001;
  9 ll a[N];
 10 int n, m;
 11
 12 struct Node
 13 {
 14     int l, r;
 15     ll sum;
 16 } node[N << 2];
 17
 18 void pushup( int i )
 19 {
 20     node[i].sum = node[i << 1].sum + node[i << 1 | 1].sum;
 21 }
 22
 23 void build( int i, int l, int r )
 24 {
 25     node[i].l = l, node[i].r = r;
 26     if ( l == r )
 27     {
 28         node[i].sum = a[l];
 29         return ;
 30     }
 31     int mid = ( l + r ) >> 1;
 32     build( i << 1, l, mid );
 33     build( i << 1 | 1, mid + 1, r );
 34     pushup(i);
 35 }
 36
 37 void update( int i, int l, int r )
 38 {
 39     int len = node[i].r - node[i].l + 1;
 40     if ( node[i].sum == len ) return ;
 41     int mid = ( node[i].l + node[i].r ) >> 1;
 42     if ( node[i].l == l && node[i].r == r )
 43     {
 44         if ( len == 1 )
 45         {
 46             node[i].sum = sqrt( node[i].sum * 1.0 );
 47         }
 48         else
 49         {
 50             update( i << 1, l, mid );
 51             update( i << 1 | 1, mid + 1, r );
 52             pushup(i);
 53         }
 54         return ;
 55     }
 56     if ( r <= mid )
 57     {
 58         update( i << 1, l, r );
 59     }
 60     else if ( l > mid )
 61     {
 62         update( i << 1 | 1, l, r );
 63     }
 64     else
 65     {
 66         update( i << 1, l, mid );
 67         update( i << 1 | 1, mid + 1, r );
 68     }
 69     pushup(i);
 70 }
 71
 72 ll query( int i, int l, int r )
 73 {
 74     if ( node[i].l == l && node[i].r == r )
 75     {
 76         return node[i].sum;
 77     }
 78     int mid = ( node[i].l + node[i].r ) >> 1;
 79     if ( r <= mid )
 80     {
 81         return query( i << 1, l, r );
 82     }
 83     else if ( l > mid )
 84     {
 85         return query( i << 1 | 1, l, r );
 86     }
 87     else
 88     {
 89         return query( i << 1, l, mid ) + query( i << 1 | 1, mid + 1, r );
 90     }
 91 }
 92
 93 int main ()
 94 {
 95     int _case = 1;
 96     while ( scanf("%d", &n) != EOF )
 97     {
 98         printf("Case #%d:\n", _case++);
 99         for ( int i = 1; i <= n; i++ )
100         {
101             scanf("%lld", &a[i]);
102         }
103         build( 1, 1, n );
104         scanf("%d", &m);
105         while ( m-- )
106         {
107             int op, x, y;
108             scanf("%d%d%d", &op, &x, &y);
109             if ( x > y ) swap( x, y );
110             if ( op == 0 )
111             {
112                 update( 1, x, y );
113             }
114             else
115             {
116                 ll ans = query( 1, x, y );
117                 printf("%lld\n", ans);
118             }
119         }
120         putchar(‘\n‘);
121     }
122     return 0;
123 }
时间: 2024-08-11 09:56:33

spoj 2713 线段树的相关文章

SPOJ GSS3 线段树系列1

SPOJ GSS系列真是有毒啊! 立志刷完,把线段树搞完! 来自lydrainbowcat线段树上的一道例题.(所以解法参考了lyd老师) 题意翻译 n 个数, q 次操作 操作0 x y把 Ax 修改为 y 操作1 l r询问区间 [l,r] 的最大子段和 数据规模在50000,有负数. 冷静分析 因为要维护最大子段和,那么我们可以在线段树struct中维护这么几个信息: sum(区间和).lmax(从左顶点出发的最大子段和).rmax(从右顶点出发的最大子段和).maxx(这段的最大子段和)

spoj GSS线段树以及二维树状数组合集

T1 维护lmax 向左延伸的最大值,rmax同理,sum区间和,ans答案. 转移见operator + #include<bits/stdc++.h> #define mid (l+(r-l)/2) #define ls (rt<<1) #define rs (rt<<1|1) #define int long long using namespace std; const int N =(int)1e5+10; struct TREE { int lef,rig,

spoj 1043 线段树

线段树在解决区间合并问题上还是很强力的,每个结点维护三个值:maxl, maxr, maxn,然后合并操作见pushup函数. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 50001; 7 int a[N]; 8 int sum[N]; 9 10 struct Node 11 { 12 int l, r; 1

spoj GSS2 (线段树) - xgtao -

题目链接 这是一道线段树的题目,维护历史版本,给出N(<=100000)个数字(-100000<=x<=100000),要求求出在[l,r]区间里面的连续序列的最大值,并且重复的数字可以加入序列但是值不能再计算. 数据范围以及区间的查询提示使用线段树,但是我们怎么建树呢?在线操作是没法做的.那就离线吧. 定义s[i] = ai + ai+1 + ai+2 + ... an,以ai开头的数列的和,那么每次加入更新ai 那么s1,s2,...si都会相应的加一个ai,s[1~i]中出现过a[

SPOJ BGSHOOT 线段树

BGSHOOT - Shoot and kill The problem is about Mr.BG who is a great hunter. Today he has gone to a dense forest for hunting and killing animals. Sadly, he has only one bullet in his gun. He wants to kill as many animals as possible with only one bulle

SPOJ GSS系列 最大子段和 线段树+树链剖分+splay 1043 1557 1716 2713 2916 4487 6779

最大子段和的各种形式 题解内附每道题的 题意 题目链接 思路 SPOJ 1043 GSS1 静态区间求个最大子段和, 题解 SPOJ 1577 GSS2 和1一样,区别是若区间内存在相同的元素,则该元素只计算一次. 离线一下然后使劲跑.. 题解 SPOJ 1716 GSS3 和1一样,就是要支持单点修改 题解 SPOJ 2713 GSS4 ==普通线段树,感觉和这系列关系不大. 题解 SPOJ 2916 GSS5 题意有点怪,,跟3差不多,就是稍加强了点询问 题解 SPOJ 4487 GSS6

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 76[Submit][Status][Discuss] Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,

SPOJ COT3 Combat on a tree(Trie树、线段树的合并)

题目链接:http://www.spoj.com/problems/COT3/ Alice and Bob are playing a game on a tree of n nodes.Each node is either black or white initially. They take turns to do the following operation:Choose a white node v from the current tree;Color all white node

SPOJ 1043 Can you answer these queries I 求任意区间最大连续子段和 线段树

题目链接:点击打开链接 维护区间左起连续的最大和,右起连续的和.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lson