BZOJ-3211花神游历各国(线段树区间开根号)
题目描述
给定一个长为 \(n(1\leq n\leq 10^5)\) 的序列 \(a(0\leq a_i\leq 10^9)\) 和 \(m(1\leq m\leq 2\times 10^5)\) 次操作,有两种操作:
操作 \(1\):1 l r,求 \(\displaystyle\sum_{i=l}^{r}a_i\)。
操作\(2\):2 l r,将每个 \(a_i(l\leq i\leq r)\) 修改为 \(\sqrt{a_i}\)。
对于每个操作 \(1\),输出一个整数表示答案。
分析
正整数 \(x\) 不超过 \(\log_2(\log_2 x)\) 次开根号操作就会变成 \(1\)(\(10^9\) 经过 \(5\) 次开根号操作就会变成 \(1\)),因此长为 \(n\) 的序列最多被修改 \(5n\) 次,在线段树节点中维护区间最大值,如果区间最大值等于 \(0\) 或 \(1\) 直接返回,不进行修改操作。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,a[N];
struct SegmentTree
{
int l,r;
long long sum;
int maxn;
}tree[N<<2];
void pushup(int p)
{
tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
tree[p].maxn=max(tree[p*2].maxn,tree[p*2+1].maxn);
}
void build(int p,int l,int r)
{
tree[p].l=l;tree[p].r=r;
if(l==r)
{
tree[p].sum=a[l];
tree[p].maxn=a[l];
return ;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void update(int p,int l,int r)
{
if(tree[p].maxn==0||tree[p].maxn==1)
return ;
if(tree[p].l==tree[p].r)
{
tree[p].sum=sqrt(tree[p].maxn);
tree[p].maxn=sqrt(tree[p].maxn);
return ;
}
int mid=(tree[p].l+tree[p].r)/2;
if(l<=mid)
update(p*2,l,r);
if(r>mid)
update(p*2+1,l,r);
pushup(p);
}
long long query(int p,int l,int r)
{
if(l<=tree[p].l&&tree[p].r<=r)
return tree[p].sum;
long long ans=0;
int mid=(tree[p].l+tree[p].r)/2;
if(l<=mid)
ans=ans+query(p*2,l,r);
if(r>mid)
ans=ans+query(p*2+1,l,r);
return ans;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
cin>>m;
while(m--)
{
int op,l,r;
scanf("%d %d %d",&op,&l,&r);
if(l>r)
swap(l,r);
if(op==1)
printf("%lld\n",query(1,l,r));
if(op==2)
update(1,l,r);
}
return 0;
}
posted on 2020-11-25 18:35 DestinHistoire 阅读(113) 评论(0) 收藏 举报
浙公网安备 33010602011771号