题目描述
"第一分钟,X说,要有数列,于是便给定了一个正整数数列。
第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。
第三分钟,k说,要能查询,于是便有了求一段数的和的操作。
第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围。
第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。
第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。"
——《上帝造题的七分钟·第二部》
所以这个神圣的任务就交给你了。
输入输出格式
输入格式:
第一行一个整数 nn ,代表数列中数的个数。
第二行 nn 个正整数,表示初始状态下数列中的数。
第三行一个整数 mm ,表示有 mm 次操作。
接下来 mm 行每行三个整数k,l,r
,
k=0
表示给 [l,r][l,r] 中的每个数开平方(下取整)k=1
表示询问 [l,r][l,r] 中各个数的和。
数据中有可能 l>rl>r ,所以遇到这种情况请交换l和r。
输出格式:
对于询问操作,每行输出一个回答。
输入输出样例
说明
对于30%的数据, 1\le n,m\le 10001≤n,m≤1000 ,数列中的数不超过 3276732767 。
对于100%的数据, 1 \le n,m \le 1000001≤n,m≤100000 , 1 \le l,r \le n1≤l,r≤n ,数列中的数大于 00 ,且不超过 10^{12}1012 。
注意l有可能大于r,遇到这种情况请交换l,r。
一道线段树的题目。
首先我们考虑一下,一个小于等于10^12的数,开了6次方之后就已经等于1了(可以自己拿计算器算一下)。而对于1,再开方也没有意义。也就是说,对每一个数,总共的开方次数只有6*n。所以我们可以开一个线段树,对于每一个修改操作,暴力修改。如果某区间的最大值为1,则跳过此区间的修改。最后基本上就是模板了
1 //minamoto 2 #include<bits/stdc++.h> 3 #define ll long long 4 #define rint register int 5 using namespace std; 6 const int N=400005; 7 int n,m;ll a[N],sum[N],maxn[N]; 8 void pushup(int p){ 9 sum[p]=sum[p<<1]+sum[p<<1|1]; 10 maxn[p]=max(maxn[p<<1],maxn[p<<1|1]); 11 } 12 void build(int p,int l,int r){ 13 if(l==r){ 14 sum[p]=maxn[p]=a[l];return; 15 } 16 int mid=(l+r)>>1; 17 build(p<<1,l,mid); 18 build(p<<1|1,mid+1,r); 19 pushup(p); 20 } 21 void change(int p,int l,int r,int ql,int qr){ 22 if(l==r){ 23 sum[p]=sqrt(sum[p]),maxn[p]=sqrt(maxn[p]);return; 24 } 25 int mid=(l+r)>>1; 26 if(ql<=mid&&maxn[p<<1]>1) change(p<<1,l,mid,ql,qr); 27 if(qr>mid&&maxn[p<<1|1]>1) change(p<<1|1,mid+1,r,ql,qr); 28 pushup(p); 29 } 30 ll query(int p,int l,int r,int ql,int qr){ 31 if(ql<=l&&qr>=r) return sum[p]; 32 int mid=(l+r)>>1; 33 ll res=0; 34 if(ql<=mid) res+=query(p<<1,l,mid,ql,qr); 35 if(qr>mid) res+=query(p<<1|1,mid+1,r,ql,qr); 36 return res; 37 } 38 int main(){ 39 scanf("%d",&n); 40 for(rint i=1;i<=n;++i) scanf("%lld",&a[i]); 41 build(1,1,n); 42 scanf("%d",&m); 43 while(m--){ 44 int opt,l,r; 45 scanf("%d%d%d",&opt,&l,&r); 46 if(l>r) swap(l,r); 47 if(opt==0) change(1,1,n,l,r); 48 else printf("%lld\n",query(1,1,n,l,r)); 49 } 50 return 0; 51 }