您的位置:首页 > 其它

[bzoj3038/3211]上帝造题的七分钟2/花神游历各国_线段树

2018-07-10 20:34 435 查看

上帝造题的七分钟2 bzoj-3038

题目大意:给定一个序列,支持:区间开方;查询区间和。

注释:$1\le n\le 10^5$,$1\le val[i] \le 10^{12}$。

想法:这题还挺挺有意思的。查询区间和我们可以用前缀和,但是用上去区间修改就不难想到线段树。那么我们思考如何在log的时间之内完成区间开方。直接打lazy显然实现不了,其实我们发现,每一个$10^{12}$之内的数最多只需要开6次方就可以变成1,$10^{12}$开6次根号是1.53993。所以我们对每一个区间用一个mark标记表示这个区间是不是全是1。如果不是的话,我就暴力修改。这样的话每一个数最多会被修改6次,所以总时间复杂度是O(n*a),a是log级别的。

P.S.:花神那道题卡读入,不加读入优化会T... ...

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 100010
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
typedef long long ll;
ll sum[N<<2],a
;
int n,m;
inline void pushup(int pos)
{
sum[pos]=sum[lson]+sum[rson];
}
void build(int pos,int l,int r)
{
if(l==r)
{
sum[pos]=a[l];
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(pos);
}
void update(int pos,int l,int r,int x,int y)
{
if(x>y)swap(x,y);
if(sum[pos]==r-l+1)return;
if(l==r)
{
sum[pos]=(ll)sqrt(sum[pos]+0.5);
return;
}
int mid=(l+r)>>1;
if(y<=mid) update(lson,l,mid,x,y);
else if(x>mid) update(rson,mid+1,r,x,y);
else update(lson,l,mid,x,y),update(rson,mid+1,r,x,y);
pushup(pos);
}
ll getsum(int pos,int l,int r,int x,int y)
{
if(x>y) swap(x,y);
if(x<=l&&r<=y) return sum[pos];
int mid=(l+r)>>1;
if(y<=mid)return getsum(lson,l,mid,x,y);
if(x>mid)return getsum(rson,mid+1,r,x,y);
return getsum(lson,l,mid,x,y)+getsum(rson,mid+1,r,x,y);
}
void output()
{
printf("Fuck : %lld\n",sum[1]);
}
int main()
{
cin >> n ;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
cin >> m ;
for(int k,x,y,i=1;i<=m;i++)
{
scanf("%d%d%d",&k,&x,&y);
if(!k) update(1,1,n,x,y);
else printf("%lld\n",getsum(1,1,n,x,y));
// output();
}
return 0;
}

小结:线段树是很神奇的...qwq

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐