您的位置:首页 > 其它

【线段树/区间开平方】BZOJ3211-花神游历各国

2016-03-08 19:00 274 查看
【题目大意】

给出一些数,有两种操作。(1)将区间内每一个数开方(2)查询每一段区间的和

【思路】

普通的线段树保留修改+开方优化。可以知道当一个数为0或1时,无论开方几次,答案仍然相同。所以设置flag=1。如果一个节点的左右孩子flag均为1,那么它的flag也是1。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
using namespace std;
const int MAXN=100000+500;
int n,m;
LL sum[MAXN<<2];
int flag[MAXN<<2];

void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
flag[rt]=flag[rt<<1]&flag[rt<<1|1];
}

void build(int l,int r,int rt)
{
flag[rt]=0;
if (l==r)
{
scanf("%lld",&sum[rt]);
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}

void update(int L,int R,int l,int r,int rt)
{
if (flag[rt]) return;
if (l==r)
{
sum[rt]=(LL)sqrt(sum[rt]);
if (sum[rt]==0 || sum[rt]==1) flag[rt]=1;
return;
}
int m=(l+r)>>1;
if (L<=m) update(L,R,lson);
if (R>m) update(L,R,rson);
pushup(rt);
}

LL query(int L,int R,int l,int r,int rt)
{
if (L<=l && r<=R) return sum[rt];
int m=(l+r)>>1;
LL ret=0;
if (L<=m) ret+=query(L,R,lson);
if (R>m) ret+=query(L,R,rson);
return ret;
}

int main()
{
scanf("%d",&n);
build(1,n,1);
scanf("%d",&m);
for (int i=0;i<m;i++)
{
int x,l,r;
scanf("%d%d%d",&x,&l,&r);
if (x==1) printf("%lld\n",query(l,r,1,n,1));
else update(l,r,1,n,1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: