Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
Source
花神系列中的水题,,当然得做做。
题目就是让你维护一个区间开平方以及区间求和的序列……
其实可以看到,即便最大最大的非高精度数字(2^63-1),开平方的话没几次就变1了。
所以其实可以对于开方操作,首先暴力开平方,
然后维护一下一段数字内是不是全部<=1和区间的和。
因为如果数字<=1就不会变了,所以不需要给它们继续开方。
这题就成了暴力+维护区间和。
以前hdu4027写过,题意基本一致。
以前写了分块,就想着贴代码……因为数据看上去差不多。
结果坑了,竟然被卡掉了1s多。。
没有办法了,,只好写一份线段树了。
比想象中写得快……而且速度也比预期快了不少。
对比一下线段树和分块的时间吧……
感觉其实两者谁更优从这道题中可以简单看到了。
但是事实上根据不同的题目,大常数的线段树还是有可能不行的呢。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll read(){
ll x=(ll)0,f=(ll)1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=(ll)-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
N=100005;
int n,q;
ll tree[N<<2],a[N];
bool mark[N<<2];
void build(int id,int l,int r){
if (l==r){
tree[id]=a[r];
if (tree[id]<=1) mark[id]=1;
return;
}
int mid=(l+r)/2;
build(id<<1,l,mid);
build((id<<1)+1,mid+1,r);
tree[id]=tree[id<<1]+tree[id<<1|1];
mark[id]=mark[id<<1]&mark[id<<1|1];
}
void update(int id,int l,int r,int gx,int gy){
if (l==r){
tree[id]=(ll)sqrt(tree[id]);
if (tree[id]<=1) mark[id]=1;
return;
}
int mid=(l+r)>>1;
if (gx<=mid && !mark[id<<1]) update(id<<1,l,mid,gx,gy);
if (gy>mid && !mark[(id<<1)+1]) update((id<<1)+1,mid+1,r,gx,gy);
tree[id]=tree[id<<1]+tree[id<<1|1];
mark[id]=mark[id<<1]&mark[id<<1|1];
}
ll query(int id,int l,int r,int gx,int gy){
if (gx<=l && gy>=r) return tree[id];
int mid=(l+r)>>1; ll pp=(ll)0;
if (gx<=mid) pp+=query(id<<1,l,mid,gx,gy);
if (gy>mid) pp+=query((id<<1)+1,mid+1,r,gx,gy);
return pp;
}
int main() {
n=read();
memset(mark,0,sizeof(mark));
for (int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
int opt,x,y; q=read();
for (int i=1;i<=q;i++){
opt=read(),x=read(),y=read();
if (opt==1)
printf("%lld\n",query(1,1,n,x,y));
else update(1,1,n,x,y);
}
return 0;
}