小清新线段树,我一直觉得是剪过枝的线段树
一般题面会有一个神奇的(暂且这么说)更改方式,而且一般没办法区间更新出值
这道题同,
√n的处理,就是在上标÷2,而且我们可以发现,0,1这两个数极棒,√0=0,√1=1,修改了和没修改一样
那么,如果我们发现区间内全是0,1,就不必修改了
而现在有两种方法可以记录(无聊的内容)
1.用bool型直接判断,不用修改的记为1,修改的记为0(便于初始化)(内存友好)
2.用maxn判断,如果最大值<=1,不必修改
非常愉快
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 101010
#define LL long long
using namespace std;
struct XDS{
int l,r,man;
LL tot;
};XDS tr[10*N];
int n,qn;
int lik[N];
void build(int l,int r,int id){
tr[id].l=l;
tr[id].r=r;
if(l==r){
tr[id].tot=lik[l];
tr[id].man=lik[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,2*id);
build(mid+1,r,2*id+1);
tr[id].tot=tr[2*id].tot+tr[2*id+1].tot;
tr[id].man=max(tr[2*id].man,tr[2*id+1].man);
}
void change(int l,int r,int id){
if(tr[id].man<=1)return;
if(tr[id].l==tr[id].r){
int e=floor(sqrt(tr[id].tot));
tr[id].tot=e;
tr[id].man=e;
return ;
}
int mid=(tr[id].l+tr[id].r)/2;
if(mid>=l){
change(l,r,id*2);
}
if(mid<r){
change(l,r,id*2+1);
}
tr[id].man=max(tr[id*2].man,tr[id*2+1].man);
tr[id].tot=tr[id*2].tot+tr[id*2+1].tot;
}
LL ffind(int l,int r,int id){
// cout<<"Ffind:"<<id<<" l"<<tr[id].l<<" r"<<tr[id].r<<" IN:"<<tr[id].tot<<"
";
if(tr[id].l>=l&&tr[id].r<=r){//puts("Addin");
return tr[id].tot;
}
LL n=0;
int mid=(tr[id].l+tr[id].r)/2;
if(mid>=l){
n+=ffind(l,r,id*2);
}
if(r>mid){
n+=ffind(l,r,id*2+1);
}
return n;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&lik[i]);
}
build(1,n,1);
scanf("%d",&qn);
int a,b,c;
for(int i=1;i<=qn;i++){
scanf("%d%d%d",&a,&b,&c);
if(a==1){
printf("%lld
",ffind(b,c,1));
}
else{
change(b,c,1);
}
}
return 0;
}
这样,我们可以愉快的A了它