P4145 上帝造题的七分钟 2 / 花神游历各国
P4145 上帝造题的七分钟 2 / 花神游历各国
题目大意:
本体总共就两个操作:
\(1.\)为将\(l\)至\(r\)区间内的所有数开根,及\(a_i=\sqrt a_i\);
\(2.\)输出\(l\)至\(r\)区间内的所有数的和
思路:
既然是区间修改和区间查询,那是个蒟蒻都能想到用线段树来维护,但我们可以发现,若一个根节点的子树开方了,那它的和也变得不确定。因此不能用懒标记来实现区间修改。可单点修改的复杂度为\(n^2\),一看就会超。但是,我们又双叒叕发现一个数顶多开\(5\)次方就会变为\(1\)或\(0\)( \(\sqrt {\sqrt{\sqrt{\sqrt{\sqrt{\sqrt {10^{12}}}}}}} \approx 1\) )而正好\(\sqrt 1=1\),所以我们只需要再维护一个区间最大值,在进行更新时看是否大于\(1\),若大于的话才需要更新
完整代码:
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define int long long
using namespace std;
const int N=101000;
int a[N];
struct edge{
int sum,max;
}tr[4*N];
inline int read(){
int x=0,w=1;
char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
void build(int p,int l,int r){
if(l==r){
tr[p].sum=a[l];
tr[p].max=a[l];
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
tr[p].sum=tr[lc].sum+tr[rc].sum;
tr[p].max=max(tr[lc].max,tr[rc].max);
}
void update(int p,int l,int r,int ll,int rr){
if(l==r && ll<=l && r<=rr){
tr[p].sum=sqrt(tr[p].sum);
tr[p].max=tr[p].sum;
return;
}
int mid=(l+r)>>1;
if(mid>=ll && tr[lc].max>1)update(lc,l,mid,ll,rr);
if(mid<rr && tr[rc].max>1)update(rc,mid+1,r,ll,rr);
tr[p].sum=tr[lc].sum+tr[rc].sum;
tr[p].max=max(tr[lc].max,tr[rc].max);
}
int query(int p,int l,int r,int ll,int rr){
if(ll<=l && r<=rr){
return tr[p].sum;
}
int res=0;
int mid=(l+r)>>1;
if(mid>=ll)res+=query(lc,l,mid,ll,rr);
if(mid<rr)res+=query(rc,mid+1,r,ll,rr);
return res;
}
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;++i){
a[i]=read();
}
build(1,1,n);
int m;
cin>>m;
int k,l,r;
for(int i=1;i<=m;++i){
k=read(),l=read(),r=read();
if(l>r)swap(l,r);
if(k==0)update(1,1,n,l,r);
else printf("%lld\n",query(1,1,n,l,r));
}
}
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18682344
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步