小清新线段树,我一直觉得是剪过枝的线段树
一般题面会有一个神奇的(暂且这么说)更改方式,而且一般没办法区间更新出值
这道题同,
√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了它