线段树『模板+例题』 上帝造题的七分钟2 / 花神游历各国

模板

区间和 为例。

ll ls(ll p) {return p<<1;}
ll rs(ll p) {return p<<1|1;}
void push_up(ll p) {
    ans[p]=ans[ls(p)]+ans[rs(p)];
}
void build(ll p,ll l,ll r) {
    tag[p]=0;
    if(l==r) {ans[p]=a[l]; return ;}
    ll Mid=(l+r)>>1;
    build(ls(p),l,Mid);
    build(rs(p),Mid+1,r);
    push_up(p);
}
void f(ll p,ll l,ll r,ll k) {
    tag[p]=tag[p]+k;
    ans[p]=ans[p]+k*(r-l+1);
}
void push_down(ll p,ll l,ll r) {
    ll Mid=(l+r)>>1;
    f(ls(p),l,Mid,tag[p]);
    f(rs(p),Mid+1,r,tag[p]);
    tag[p]=0;
}
void update(ll nl,ll nr,ll p,ll l,ll r,ll k) {
    if(nl<=l&&r<=nr) {
        tag[p]+=k;
        ans[p]+=k*(r-l+1);
        return ;
    }
    push_down(p,l,r);
    ll Mid=(l+r)>>1;
    if(nl<=Mid) update(nl,nr,ls(p),l,Mid,k);
    if(nr>Mid) update(nl,nr,rs(p),Mid+1,r,k);
    push_up(p);
}
ll query(ll ql,ll qr,ll p,ll l,ll r) {
    ll res=0;
    if(ql<=l&&r<=qr) return ans[p];
    ll Mid=(l+r)>>1;
    push_down(p,l,r);
    if(ql<=Mid) res+=query(ql,qr,ls(p),l,Mid);
    if(qr>Mid) res+=query(ql,qr,rs(p),Mid+1,r);
    return res;
}

 

例题

题面

分析

因为数列中的数$le 10^{12}$,所以最多开方$6$次就可变为$1$。

当一个数已经等于$0$或$1$时,再开方就没有意义了(值不变)

因此当线段树中某个叶子节点的值为$0$或$1$时,就给它打标记,可以不再操作。

同样,某个父亲节点的两个子节点都被标记时,也给它打标记。

详情见代码

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=1e5+5;
 5 int n,m;
 6 ll a[N],sum[N<<2];
 7 bool tag[N<<2];
 8 inline ll read() {
 9     ll x=0; char c=getchar();
10     while(c<'0'||c>'9') c=getchar();
11     while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
12     return x;
13 }
14 
15 inline int ls(int p) {return p<<1;}
16 inline int rs(int p) {return p<<1|1;}
17 void push_up(int p) {
18     sum[p]=sum[ls(p)]+sum[rs(p)];
19     tag[p]=tag[ls(p)]&&tag[rs(p)];
20 }
21 void build(int p,int l,int r) {
22     if(l==r) {sum[p]=a[l]; return ;}
23     int Mid=(l+r)>>1;
24     build(ls(p),l,Mid);
25     build(rs(p),Mid+1,r);
26     push_up(p);
27 }
28 void update(int nl,int nr,int p,int l,int r) {
29     if(tag[p]) return ;
30     if(l==r) {
31         sum[p]=sqrt(sum[p]);
32         if(sum[p]==0||sum[p]==1) tag[p]=1;
33         return ;
34     }
35     int Mid=(l+r)>>1;
36     if(nl<=Mid) update(nl,nr,ls(p),l,Mid);
37     if(Mid<nr) update(nl,nr,rs(p),Mid+1,r);
38     push_up(p); 
39 }
40 ll query(int ql,int qr,int p,int l,int r) {
41     ll res=0;
42     if(ql<=l&&r<=qr) return sum[p];
43     int Mid=(l+r)>>1;
44     if(ql<=Mid) res+=query(ql,qr,ls(p),l,Mid);
45     if(Mid<qr) res+=query(ql,qr,rs(p),Mid+1,r);
46     return res;
47 }
48 
49 int main() {
50     n=read();
51     for(int i=1;i<=n;i++) a[i]=read();
52     build(1,1,n);
53     m=read();
54     while(m--) {
55         int k=read(),l=read(),r=read();
56         if(l>r) swap(l,r);
57         if(k==0) update(l,r,1,1,n);
58         else printf("%lld
",query(l,r,1,1,n));
59     }
60 }