洛谷P4145 上帝造题的七分钟 2 / 花神游历各国 题解
题目链接:P4145 上帝造题的七分钟 2 / 花神游历各国
题意:维护一个数据结构
区间
sqrt()
(对每个数开平方+下取整)询问区间和
$\sqrt{a+b} \ne \sqrt{a}+\sqrt{b}$
因此无法用线段树维护
那么怎么搞呢?注意到数据范围中,每个数都为正整数,且不超过 $10^{12}$
$\sqrt{1}=1$
$\left(10^{12}\right)^{2^{-6}} \approx 1$
可以发现,对于一个数,最多进行 $6$ 次sqrt()
操作,它就变成 $1$ 不变了
于是我们还是用线段树,每次修改直接暴力递归到叶子节点进行修改
诶?不是说不能用线段树吗?怎么又用了?
因为区间和是可以用线段树维护的呀!qwq 只不过这个开平方没法维护,直接“暴力”
根据势能分析,可知
时间复杂度( $n,m$ 同阶 )
代码如下
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e6+15)
char buf1[SIZ],*p1,*p2;
char readchar()
{
if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
char ch=gc();T x=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
k=x*f;
}
template<typename T>void write(T k)
{
if(k<0){k=-k;pc('-');}
static T stk[66];T top=0;
do{stk[top++]=k%10,k/=10;}while(k);
while(top){pc(stk[--top]+'0');}
}
}using namespace FastIO;
#define N (int)(1e5+15)
#define ls(at) (at<<1)
#define rs(at) (at<<1|1)
int n,a[N];
int mx[N<<2],sum[N<<2];
void push_up(int at)
{
mx[at]=max(mx[ls(at)],mx[rs(at)]);
sum[at]=sum[ls(at)]+sum[rs(at)];
}
void build(int l,int r,int at)
{
if(l==r)
{
sum[at]=mx[at]=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,ls(at));
build(mid+1,r,rs(at));
push_up(at);
}
void update(int nl,int nr,int l,int r,int at)
{
if(l==r)
{
sum[at]=sqrt(sum[at]);
mx[at]=sqrt(mx[at]);
return;
}
int mid=(l+r)>>1;
if(nl<=mid&&mx[ls(at)]>1)
update(nl,nr,l,mid,ls(at));
if(nr>mid&&mx[rs(at)]>1)
update(nl,nr,mid+1,r,rs(at));
push_up(at);
}
int query(int nl,int nr,int l,int r,int at)
{
if(nl<=l&&r<=nr)return sum[at];
if(nl>r||nr<l)return 0;
int mid=(l+r)>>1;
return query(nl,nr,l,mid,ls(at))+query(nl,nr,mid+1,r,rs(at));
}
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
read(n);
for(int i=1; i<=n; i++)
read(a[i]);
build(1,n,1);
int Q;read(Q);
while(Q--)
{
int op,l,r;
read(op);read(l);read(r);
if(l>r)swap(l,r);
if(op==0)
update(l,r,1,n,1);
else write(query(l,r,1,n,1)),pc('\n');
}
return 0;
}