SP2713 GSS4 - Can you answer these queries IV
「题意」: n 个数,每个数在(10^{18}) 范围内。
现在有「两种」操作
0 x y
把区间([x,y]) 内的每个数开方
1 x y
询问区间([x,y]) 的每个数的和「格式」: 有多组数据,数据以EOF结束,对于每组数据,输出数据的序号,每组数据之后输出一个空行。
「注意」: 不保证给出的区间([x, y]) 有x<=y ,如果x>y 请交换x ,y 。
之前做过花神那个题,但是是考试题,没有认真改。。。
模了大佬@cellur925的题解才会。
原来真的是暴力,但是一个(1*10^9)的数最多开方5次就会降低到1到2之间。这个时候就不用开方了。
复杂度依旧是(mlogn),加了一个类似(log)的常数,差不多是5,6。
code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define int long long
#define ls(o) o<<1
#define rs(o) o<<1|1
using namespace std;
const int wx=200017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
struct val_tree{
int l,r,sum,ma;
#define sum(o) t[o].sum
#define ma(o) t[o].ma
}t[wx*4];
int a[wx];
int n,m;
void up(int o){
sum(o)=sum(ls(o))+sum(rs(o));
ma(o)=max(ma(ls(o)),ma(rs(o)));
}
void build(int o,int l,int r){
t[o].l=l;t[o].r=r;
if(l==r){sum(o)=ma(o)=a[l];return;}
int mid=t[o].l+t[o].r>>1;
if(l<=mid)build(ls(o),l,mid);
if(r>mid)build(rs(o),mid+1,r);
up(o);
}
void update(int o,int l,int r){
if(t[o].l==t[o].r){
sum(o)=(int)sqrt(sum(o));
ma(o)=(int)sqrt(ma(o));
return ;
}
int mid=t[o].l+t[o].r>>1;
if(l<=mid&&ma(ls(o))>1)update(ls(o),l,r);
if(r>mid&&ma(rs(o))>1)update(rs(o),l,r);
up(o);
}
int query(int o,int l,int r){
if(l<=t[o].l&&t[o].r<=r){
return sum(o);
}
int mid=t[o].l+t[o].r>>1;
int sum=0;
if(l<=mid)sum+=query(ls(o),l,r);
if(r>mid)sum+=query(rs(o),l,r);
return sum;
}
signed main(){
int cnt=0;
while(~scanf("%lld",&n)){
cnt++;
memset(a,0,sizeof a);
memset(t,0,sizeof t);
printf("Case #%lld:
",cnt);
for(int i=1;i<=n;i++)a[i]=read();
build(1,1,n);
m=read();
for(int i=1,opt,x,y;i<=m;i++){
opt=read();x=read();y=read();
if(x>y)swap(x,y);
if(opt)printf("%lld
",query(1,x,y));
else update(1,x,y);
}
puts("");
}
}