BZOJ 3038: 上帝造题的七分钟2【线段树区间开方问题】

3038: 上帝造题的七分钟2

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1469  Solved: 631
[Submit][Status][Discuss]

Description

XLk觉得《上帝造题的七分钟》不太过瘾,于是有了第二部。
"第一分钟,X说,要有数列,于是便给定了一个正整数数列。
第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。
第三分钟,k说,要能查询,于是便有了求一段数的和的操作。
第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围。
第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。
第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。"
——《上帝造题的七分钟·第二部》
所以这个神圣的任务就交给你了。

Input

第一行一个整数n,代表数列中数的个数。
第二行n个正整数,表示初始状态下数列中的数。
第三行一个整数m,表示有m次操作。
接下来m行每行三个整数k,l,r,k=0表示给[l,r]中的每个数开平方(下取整),k=1表示询问[l,r]中各个数的和。

Output

对于询问操作,每行输出一个回答。

Sample Input

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

Sample Output

19
7
6

HINT

1:对于100%的数据,1<=n<=100000,1<=l<=r<=n,数列中的数大于0,且不超过1e12。

2:数据不保证L<=R 若L>R,请自行交换L,R,谢谢!

Source

Poetize4

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3038

分析:开方操作的标记是不能合并的,怎么办呢

每个数最大都是1e12,开一次方成了1e6,然后1e3…可以看出来下降的十分迅速,当它到1或者0的时候再开方就没意义了…

所以线段树记录最大值,每次递归左右儿子时若最大值大于1则递归,每次修改区间暴力修改,没几次这个线段树就基本不递归了…

下面给出AC代码:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 inline ll read()
  5 {
  6     ll x=0,f=1;
  7     char ch=getchar();
  8     while(ch<‘0‘||ch>‘9‘)
  9     {
 10         if(ch==‘-‘)
 11             f=-1;
 12         ch=getchar();
 13     }
 14     while(ch>=‘0‘&&ch<=‘9‘)
 15     {
 16         x=x*10+ch-‘0‘;
 17         ch=getchar();
 18     }
 19     return x*f;
 20 }
 21 const ll N=100010;
 22 ll a[N];
 23 struct data
 24 {
 25     ll L,R;
 26     ll sum;
 27     bool flag;
 28 }tree[N<<2];
 29 ll n,m;
 30 inline void buildtree(ll l,ll r,ll pos)
 31 {
 32     tree[pos].L=l;
 33     tree[pos].R=r;
 34     if(l==r)
 35     {
 36         tree[pos].sum=a[l];
 37         if(a[l]==1||a[l]==0)
 38             tree[pos].flag=1;
 39         return;
 40     }
 41     ll mid=(l+r)/2;
 42     buildtree(l,mid,pos*2);
 43     buildtree(mid+1,r,pos*2+1);
 44     tree[pos].sum=tree[pos*2].sum+tree[pos*2+1].sum;
 45     tree[pos].flag=tree[pos*2].flag&tree[pos*2+1].flag;
 46 }
 47 inline void update(ll l,ll r,ll pos)
 48 {
 49     if(tree[pos].flag)
 50         return;
 51     if(tree[pos].L==tree[pos].R)
 52     {
 53         tree[pos].sum=(ll)sqrt(tree[pos].sum);
 54         if(tree[pos].sum==1||tree[pos].sum==0)
 55             tree[pos].flag=1;
 56         return;
 57     }
 58     ll mid=(tree[pos].L+tree[pos].R)/2;
 59     if(mid>=r)
 60         update(l,r,pos*2);
 61     else if(mid<l)
 62         update(l,r,pos*2+1);
 63     else
 64     {
 65         update(l,mid,pos*2);
 66         update(mid+1,r,pos*2+1);
 67     }
 68     tree[pos].sum=tree[pos*2].sum+tree[pos*2+1].sum;
 69     tree[pos].flag=tree[pos*2].flag&tree[pos*2+1].flag;
 70 }
 71 inline ll Query(ll l,ll r,ll pos)
 72 {
 73     if(tree[pos].L==l&&tree[pos].R==r)
 74         return tree[pos].sum;
 75     ll mid=(tree[pos].L+tree[pos].R)/2;
 76     if(mid>=r)
 77         return Query(l,r,pos*2);
 78     else if(mid<l)
 79         return Query(l,r,pos*2+1);
 80     else
 81         return Query(l,mid,pos*2)+Query(mid+1,r,pos*2+1);
 82 }
 83 int main()
 84 {
 85     n=read();
 86     for(ll i=1;i<=n;i++)
 87         a[i]=read();
 88     buildtree(1,n,1);
 89     m=read();
 90     for(ll i=1;i<=m;i++)
 91     {
 92         ll pos,l,r;
 93         pos=read();
 94         l=read();
 95         r=read();
 96         if(l>r)
 97             swap(l,r);
 98         if(!pos)
 99             update(l,r,1);
100         else
101             printf("%lld\n",Query(l,r,1));
102     }
103     return 0;
104 }
时间: 2024-10-13 15:53:38

BZOJ 3038: 上帝造题的七分钟2【线段树区间开方问题】的相关文章

bzoj 3038: 上帝造题的七分钟2 线段树||hdu 4027

3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1066  Solved: 476[Submit][Status][Discuss] Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部."第一分钟,X说,要有数列,于是便给定了一个正整数数列.第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作.第三分钟,k说,要能查询,于是便有了求一段数的和的操作.第四分

3038: 上帝造题的七分钟2 [线段树 暴力]

3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1210  Solved: 536[Submit][Status][Discuss] Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部."第一分钟,X说,要有数列,于是便给定了一个正整数数列.第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作.第三分钟,k说,要能查询,于是便有了求一段数的和的操作.第四分

BZOJ 3038 上帝造题的七分钟2 (并查集+树状数组)

题解:同 BZOJ 3211 花神游历各国,需要注意的是需要开long long,还有左右节点需要注意一下. #include <cstdio> #include <cmath> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; LL a[100005],c[100005]; int f[100005],n,m,op,l,r,t; int s

BZOJ 3038 上帝造题的七分钟2 树状数组+并查集

题目大意:一个序列,有两种操作,1.将一段数中的每一个数开根号.2.查询一段数的和. 思路:和3211是一个题,有兴趣的可以看看我的那篇博客. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 using namespace std; int cnt,asks

BZOJ 3038 上帝造题的七分钟2

我们发现每个数被开平方的次数不是太多. 然后1开平方还是1. 然后怎么办? 暴力啊!只要找到没有1的地方暴力做就可以了. #include<iostream>#include<cstdio>#include<cstring>#include<cmath>#define maxn 100500using namespace std;long long ls[maxn<<3],rs[maxn<<3],value[maxn<<3

【BZOJ3038】上帝造题的七分钟2 线段树

根据一个数六次√必死,我们可以打标记死了就不管他了,于是有贡献的操作复杂度为O(n*logn*6),然而我们还有由于盲目修改造成的多余代价我们把每次查询的区间分成三部分前全死,中残,后全死,对于中残,我们的操作都是由于为了有价值的操作而操作的,(无论中间残的那里面断断续续的死的是多长,他的向下都是为了做出贡献),而两边的多余费用最多O(4*logn),最终约为O(10*n*logn) #include<cstdio> #include<cmath> #include<cstr

3038: 上帝造题的七分钟2

3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 662  Solved: 302[Submit][Status] Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部."第一分钟,X说,要有数列,于是便给定了一个正整数数列.第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作.第三分钟,k说,要能查询,于是便有了求一段数的和的操作.第四分钟,彩虹喵说,要是n

BZOJ 3132: 上帝造题的七分钟( 二维BIT )

二维树状数组... 自己YY一下再推一下应该可以搞出来... ---------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i , n ) for( int i = 0 ; i <

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第