zoukankan      html  css  js  c++  java
  • 线段树『模板+例题』

    模板

    区间和 为例。

    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;
    }

     

    例题

    上帝造题的七分钟2 / 花神游历各国

    题面

    分析

    因为数列中的数$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 }
  • 相关阅读:
    第002篇 深入体验C#项目开发(一)
    C#编程打字指法练习
    第001篇——C#学习计划开启
    2020杭电多校第一场(待更新)
    LeetCode双周赛11
    LeetCode双周赛10
    LeetCode Weekly 156
    NOIP模板复习(4)区间操作之莫队算法,树状数组,线段树
    NOIP模板复习(3) 最短路三巨头Floyd,Dijkstra与SPFA
    NOIP模板复习(2) LCA的三种解法
  • 原文地址:https://www.cnblogs.com/qq8260573/p/10426175.html
Copyright © 2011-2022 走看看