ツリーラインの学習教材

はじめに:

何かを学ぶために、データ構造の完成に行くことにしました、その結果は今までグーとなっています。

セグメントツリーは、高度なデータ構造です。

これは、セグメントのために、私たちは、二分木で表現されているバイナリツリー、です。

本体:

セグメントツリーは照会、修正のシングルポイント、クエリー間隔、間隔修正の単一のポイントを行うことができます......

一般的なセグメントツリーがあります

のは、例を挙げてみましょう

今、私は数字のように文字列を持っています:

ツリーラインで彼を入れて、それはケースのようになります。

そして、各リーフノードは、彼の息子の値の父であり、これは一般的なツリーラインです:

私たちは、番号の付いたために、すべてのノードを置く:

私たちは、各ノードの息子とそのシリアルナンバーことがわかりました数自体は、独自のシリアル番号がある----関係は、彼の息子の番号左2Aに、右側数の息子2A + 1そこで、我々は、再帰的にダウンしたツリーラインから構築しました。

定義

int input[500005];//用来存放输入的数组。
struct node{
    int l,r,sum;//l和r分别表示当前节点表示的范围,sum是这个节点的值。
}tree[4*500005];//线段树的空间要开到原数组的4倍,否则会死的很惨。

貢献

void build(int i,int l,int r){//递归建树,一般来说,调用的时候,i的位置填1,l和r分别填输入的数组的第一个序号和最后一个序号。
   tree[i].l=l;tree[i].r=r;
   if(l==r){//如果这个节点是叶子节点
       tree[i].sum=input[l];
       return ;
   }
   int mid=(l+r)>>1;
   build(i*2,l,mid);
   build(i*2+1,mid+1,r);//分别构造左子树和右子树
   tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;//然后由儿子推到父亲。
    return ;
}

次に、我々はいくつかの基本的な操作を学びに来ます

間隔の変更

この間隔が完全にターゲットゾーン内部に含まれている場合、このセクションのフラグkを伝えます

コード

inline void add(int i,int l,int r,int k){
    if(tree[i].l>=l && tree[i].r<=r){//如果这个区间被完全包括在目标区间里面,讲这个区间标记k
        tree[i].sum+=k;
        return ;
    }
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
}

お問い合わせのシングルポイント

お問い合わせのいわゆるシングルポイント数がある*操作の現在の値の食事の簡単な計算の後にあなたを依頼することです。

ただ、このチャートに、例えば:私は、数5の値を知りたいです。

これは、次のような検索を生み出します

ノードは、直接出力される発生した場合、検索の範囲は、ノードを決定することです。ノードは、この年に含まれている場合、それは洗練を続けています。

コード

void search(int i,int dis){
    if(tree[i].l==tree[i].r) {
         return tree[i].sum;
    }
    int mid=(tree[i].l+tree[i].r)/2;
    if(dis<=mid) return search(i*2,dis);
    else return search(i*2+1,dis);
}

-------------------------------------------------- - 分割線----------------------------------------------- -------------------------------

インターバル・お問い合わせ

問い合わせのほぼ一点は、問い合わせの単一点(の範囲がある)として理解することができます。いくつかのノードは、まさにこの範囲が含まれている、あなたは直接フレーズを追加することができます。

コード

int search(int i,int l,int r){
    if(tree[i].l>=l&&tree[i].r<=r)
        return tree[i].sum;
    if(tree[i].r<l||tree[i].l>r) return 0;
    int s=0;
    if(tree[i*2].r>=1) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s;
}

修正のシングルポイント

当社の業績が下から上に構築されて、一点の修正時間がある限り、ターゲットノードがプラスのポイントが含まれているとして、トップダウンから変更されてその上に同じ番号です。

コード

inline void add(int i,int dis,int k){
    if(tree[i].l==tree[i].r){
        tree[i].sum+=k;
        return;
    }
    if(dis<=tree[i*2].r&&dis>=tree[i*2].l) tree[i].sum+=k,add(i*2,dis,k);
    else if(dis<=tree[i*2+1].r&&dis>=tree[i*2+1].l) tree[i].sum+=k,add(i*2+1,dis,k);
}

注:上記のセクションとクエリ間隔を変更するには、あなたはその理由を知っているだろうに読み、共有することはできません

今、私たちは、変更とクエリの間隔を実装する必要があります。2つのプット上記のクエリ間隔にしたいときに問題があるでしょうが完全に改訂されたセクションに含まれていない場合、我々は怠惰なマークを使用する必要があるので、問題があるでしょう。

原理:上記の状況が発生した場合、第一下流怠惰なマーカーは、決意。

コード(つまり、コード・セグメント・ツリー・テンプレート・質問1)

void pushdown(ll i){
    if(tree[i].lazy!=0){
        tree[i*2].lazy+=tree[i].lazy;
        tree[i*2+1].lazy+=tree[i].lazy;
        ll mid=(tree[i].l+tree[i].r)/2;
        tree[i*2].num+=tree[i].lazy*(mid-tree[i*2].l+1);
        tree[i*2+1].num+=tree[i].lazy*(tree[i*2+1].r-mid);
        tree[i].lazy=0;
    }
    return ;
}
void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<=r&&tree[i].l>=l) {
        tree[i].num+=k*(tree[i].r-tree[i].l+1);
        tree[i].lazy+=k;
        return;
    }
    pushdown(i);
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
    return;
} 

ll search(ll i,ll l,ll r)
{
    if(tree[i].l>=l && tree[i].r<=r)
    return tree[i].num;
    if(tree[i].r<l||tree[i].l>r) return 0;
    pushdown(i);
    ll s=0;
    if(tree[i*2].r>=l) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s; 
}

オンラインセグメントテンプレートツリー乗算は2に登場しました

異なる事業者の、操作の順序は同じではありませんので、この時点では、同じことが、さらに好きではなかったです。

これは、我々が検討する必要があり、下を通過する際に怠惰なラベルマークでしょう、最初に増加し、最初または一緒に取るを取ることです。私達はちょうどそう怠惰なマークにプロセスを行う必要があります。

レイジーマークは2、すなわち、加算や乗算プラザMLZに分かれています。

上記同様に、コード、機能の複数の

(セグメントツリーテンプレート質問2)コード

 void pushdown(ll i){
    ll k1=tree[i].mlz,k2=tree[i].plz;
    tree[i<<1].sum=(tree[i<<1].sum*k1+k2*(tree[i<<1].r-tree[i<<1].l+1))%p;
    tree[i<<1|1].sum=(tree[i<<1|1].sum*k1+k2*(tree[i<<1|1].r-tree[i<<1|1].l+1))%p;
    tree[i<<1].mlz=(tree[i<<1].mlz*k1)%p;
    tree[i<<1|1].mlz=(tree[i<<1|1].mlz*k1)%p;
    tree[i<<1].plz=(tree[i<<1].plz*k1+k2)%p;
    tree[i<<1|1].plz=(tree[i<<1|1].plz*k1+k2)%p;
    tree[i].plz=0;
    tree[i].mlz=1;
    return ;
}
inline void mul(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum=(tree[i].sum*k)%p;
        tree[i].mlz=(tree[i].mlz*k)%p;
        tree[i].plz=(tree[i].plz*k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  mul(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  mul(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum+=((tree[i].r-tree[i].l+1)*k)%p;
        tree[i].plz=(tree[i].plz+k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  add(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  add(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
ll search(ll i,ll l,ll r){
    if(tree[i].r<l || tree[i].l>r)  return 0;
    if(tree[i].l>=l && tree[i].r<=r)
        return tree[i].sum;
    pushdown(i);
    ll sum=0;
    if(tree[i<<1].r>=l)  sum+=search(i<<1,l,r)%p;
    if(tree[i<<1|1].l<=r)  sum+=search(i<<1|1,l,r)%p;
    return sum%p;
}

最後に、コードテンプレート4つの質問を、約入れ

[テンプレート]フェンウィックツリー1

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0;
    int f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + (ch ^ 48);
        ch = getchar();
    }
    x *= f;
    return;
}
template <typename T>
inline void write(T x)
{
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}
int n,m,p;
int input[500005];
struct node{
    int l,r,sum;
}tree[4*500005];
inline void build(int i,int l,int r){
    tree[i].l=l,tree[i].r=r;
    if(l==r){
        tree[i].sum=input[l];
        return;
    }
    int mid=(l+r)>>1;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
    return;
}
inline int search(int i,int l,int r){
    if(tree[i].l>=l&&tree[i].r<=r)
        return tree[i].sum;
    if(tree[i].r<l||tree[i].l>r) return 0;
    int s=0;
    if(tree[i*2].r>=1) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s;
}
inline void add(int i,int dis,int k){
    if(tree[i].l==tree[i].r){
        tree[i].sum+=k;
        return;
    }
    if(dis<=tree[i*2].r) add(i*2,dis,k);
    else add(i*2+1,dis,k);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}

int main(){
    int a,b,c,d;
    read(n),read(m);
    for(int i=1;i<=n;i++)
        read(input[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        read(a),read(b),read(c);
        if(a==1){
            add(1,b,c);
        }
        else{
            write(search(1,b,c)),cout<<endl;
        }
    }
}

[テンプレート]フェンウィックツリー2

#include<bits/stdc++.h>
using namespace std;
template <typename T>
void read(T &x) {
    x = 0;
    int f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + (ch ^ 48);
        ch = getchar();
    }
    x *= f;
    return;
}
template <typename T>
void write(T x)
{
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}

int n,m,a,b,c,ans,f;
struct Tree{
    int l,r,num;
}tree[500005*4]; 
int input[500005];
inline void build(int i,int l,int r){
    tree[i].l=l,tree[i].r=r;
    if(l==r){
        tree[i].num=input[l];
        return;
    }
    int mid=(l+r)/2;
    build(i*2,l,mid);build(i*2+1,mid+1,r);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
}

inline void add(int i,int l,int r,int k)
{
    if(tree[i].l>=l&&tree[i].r<=r){
        tree[i].num+=k;
        return;
    }
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
}
inline void search(int i,int dis){//此处的代码和上文讲的不太一样,都可以。
    ans+=tree[i].num;
    if(tree[i].l==tree[i].r) {
         return ;
    }
    int mid=(tree[i].l+tree[i].r)/2;
    if(dis<=mid) search(i*2,dis);
    if(dis>mid) search(i*2+1,dis);
}
int main(){
    read(n),read(m);
    build(1,1,n);
    for(int i=1;i<=n;i++)
        read(input[i]);
    for(int i=1;i<=m;i++)
    {
        read(f);
        if(f==1){
            read(a),read(b),read(c);
            add(1,a,b,c);
        }
        else{
            ans=0;
            read(a);
            search(1,a);
            cout<<ans+input[a]<<endl;
        }
        
    }
}

[テンプレート]、セグメントツリー1

#include<bits/stdc++.h>
#define ll long long
using namespace std;

template <typename T>
inline void read(T &x) {
    x = 0;
    ll f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + (ch ^ 48);
        ch = getchar();
    }
    x *= f;
    return;}
template <typename T>
inline void write(T x){
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        write(x/10);
    putchar(x % 10 + '0');
    return;
}

ll n,m,input[500005],a,b,c,d;
struct Tree{
    ll l,r,num,lazy;
}tree[500005*4];
inline void build(ll i,ll l,ll r){
    tree[i].l=l,tree[i].r=r;
    if(l==r){
        tree[i].num=input[l];
        return;
    }
    ll mid=(l+r)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
}
inline void pushdown(ll i){
    if(tree[i].lazy!=0){
        tree[i*2].lazy+=tree[i].lazy;
        tree[i*2+1].lazy+=tree[i].lazy;
        ll mid=(tree[i].l+tree[i].r)/2;
        tree[i*2].num+=tree[i].lazy*(mid-tree[i*2].l+1);
        tree[i*2+1].num+=tree[i].lazy*(tree[i*2+1].r-mid);
        tree[i].lazy=0;
    }
    return ;
}
inline void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<=r&&tree[i].l>=l) {
        tree[i].num+=k*(tree[i].r-tree[i].l+1);
        tree[i].lazy+=k;
        return;
    }
    pushdown(i);
    if(tree[i*2].r>=l)
        add(i*2,l,r,k);
    if(tree[i*2+1].l<=r)
        add(i*2+1,l,r,k);
    tree[i].num=tree[i*2].num+tree[i*2+1].num;
    return;
} 

inline ll search(ll i,ll l,ll r)
{
    if(tree[i].l>=l && tree[i].r<=r)
    return tree[i].num;
    if(tree[i].r<l||tree[i].l>r) return 0;
    pushdown(i);
    ll s=0;
    if(tree[i*2].r>=l) s+=search(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);
    return s; 
}
int main(){
    read(n),read(m);
    for(register ll i=1;i<=n;i++)   
        read(input[i]);
    build(1,1,n);
    for(register ll i=1;i<=m;i++){
        read(d);
        if(d==1) read(a),read(b),read(c),add(1,a,b,c);
        else read(a),read(b),write(search(1,a,b)),cout<<'\n';
    }
} 

[テンプレート]、セグメントツリー2

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,p;
ll input[100010];
struct node{
    ll l,r;
    ll sum,mlz,plz;
}tree[4*100010];
inline void build(ll i,ll l,ll r){
    tree[i].l=l;
    tree[i].r=r;
    tree[i].mlz=1;
    if(l==r){
        tree[i].sum=input[l]%p;
        return ;
    }
    ll mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
inline void pushdown(ll i){
    ll k1=tree[i].mlz,k2=tree[i].plz;
    tree[i<<1].sum=(tree[i<<1].sum*k1+k2*(tree[i<<1].r-tree[i<<1].l+1))%p;
    tree[i<<1|1].sum=(tree[i<<1|1].sum*k1+k2*(tree[i<<1|1].r-tree[i<<1|1].l+1))%p;
    tree[i<<1].mlz=(tree[i<<1].mlz*k1)%p;
    tree[i<<1|1].mlz=(tree[i<<1|1].mlz*k1)%p;
    tree[i<<1].plz=(tree[i<<1].plz*k1+k2)%p;
    tree[i<<1|1].plz=(tree[i<<1|1].plz*k1+k2)%p;
    tree[i].plz=0;
    tree[i].mlz=1;
    return ;
}
inline void mul(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum=(tree[i].sum*k)%p;
        tree[i].mlz=(tree[i].mlz*k)%p;
        tree[i].plz=(tree[i].plz*k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  mul(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  mul(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
inline void add(ll i,ll l,ll r,ll k){
    if(tree[i].r<l || tree[i].l>r)  return ;
    if(tree[i].l>=l && tree[i].r<=r){
        tree[i].sum+=((tree[i].r-tree[i].l+1)*k)%p;
        tree[i].plz=(tree[i].plz+k)%p;
        return ;
    }
    pushdown(i);
    if(tree[i<<1].r>=l)  add(i<<1,l,r,k);
    if(tree[i<<1|1].l<=r)  add(i<<1|1,l,r,k);
    tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%p;
    return ;
}
inline ll search(ll i,ll l,ll r){
    if(tree[i].r<l || tree[i].l>r)  return 0;
    if(tree[i].l>=l && tree[i].r<=r)
        return tree[i].sum;
    pushdown(i);
    ll sum=0;
    if(tree[i<<1].r>=l)  sum+=search(i<<1,l,r)%p;
    if(tree[i<<1|1].l<=r)  sum+=search(i<<1|1,l,r)%p;
    return sum%p;
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&p);
    for(int i=1;i<=n;i++)  scanf("%lld",&input[i]);
    build(1,1,n); 
    for(int i=1;i<=m;i++){
        ll f1,a,b,c;
        scanf("%lld",&f1);
        if(f1==1)
            scanf("%lld%lld%lld",&a,&b,&c),mul(1,a,b,c);
        if(f1==2)
            scanf("%lld%lld%lld",&a,&b,&c),add(1,a,b,c);
        if(f1==3)
            scanf("%lld%lld",&a,&b),printf("%lld\n",search(1,a,b));
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/iloveori/p/12525886.html