zoukankan      html  css  js  c++  java
  • 数据结构:线段树

    直接上干货首先是定义:

    const int maxn=100005,maxq=100005;
    int n,q;
    long long a[maxn];
    struct tree
    {
        long long sum,lazy;
        long long _max,_min;
        bool v;
        int l,r;
    }t[4*maxn];

    这里开了4倍结点大小的,用的时候建议改成3,因为啥呢,我们是根据满二叉树(这里虽然是完全二叉树)的最后一层结点数量来确定整个树的结点数量,如果最后一层的结点数量为n,那么整个树的结点数量是2倍还多,开3还是比较合适的,如果比较极限的话,有必要看一下到底开多少

    然后是建树:

    void buildtree(int l,int r,int o)
    {
        t[o].l=l,t[o].r=r;
        if(t[o].l==t[o].r)
        {
            t[o].sum=t[o]._max=t[o]._min=a[l];
            return;
        }
        int ch=o*2;
        int m=(l+r)/2;
        buildtree(l,m,ch);
        buildtree(m+1,r,ch+1);
        t[o].sum=t[ch].sum+t[ch+1].sum;
        t[o]._max=max(t[ch]._max,t[ch+1]._max);
        t[o]._min=min(t[ch]._min,t[ch+1]._min);
    }

    我们要维护什么,就要在建树的时候加以体现

    然后是释放懒标记,这里其实是有一定难度的,因为你要根据实际的情况来调整你释放懒标记的策略,比如说打了重置标记和没打重置标记的时候,释放懒标记的情况就是不一样的,具体问题具体分析

    这里是线段树最大的难点

    void release(int o)
    {
        if(t[o].lazy==0&&t[o].v==0)
            return;
        int ch=o*2;
        int flag=1;
        if(t[o].v)
        {
            t[o].sum=(t[o].r-t[o].l+1)*t[o].lazy;
            t[o]._max=t[o]._min=t[o].lazy;
            if(t[o].l!=t[o].r)
            {
                t[ch].lazy=t[ch+1].lazy=t[o].lazy;
                t[ch].v=t[ch+1].v=true;
            }
            t[o].v=false;
            flag=0;
        }
        if(flag)
        {
            t[o].sum+=(t[o].r-t[o].l+1)*t[o].lazy;
            t[o]._max+=t[o].lazy;
            t[o]._min+=t[o].lazy;
            if(t[o].l!=t[o].r)
            {
                t[ch].lazy+=t[o].lazy;
                t[ch+1].lazy+=t[o].lazy;
            }
        }
        t[o].lazy=0;
    }

    接下来我们给出区间重置的函数,其本质就是打重置标记:

    void reset(int l,int r,long long x,int o)
    {
        int ch=o*2;
        if(t[o].l==l&&t[o].r==r)
        {
            t[o].lazy=x;
            t[o].v=true;
            release(o);
            return;
        }
        release(o);
        int m=(t[o].l+t[o].r)/2;
        if(r<=m)
        {
            reset(l,r,x,ch);
            release(ch+1);
        }
        if(l>m)
        {
            reset(l,r,x,ch+1);
            release(ch);
        }
        if(l<=m&&r>m)
        {
            reset(l,m,x,ch);
            reset(m+1,r,x,ch+1);
        }
        t[o].sum=t[ch].sum+t[ch+1].sum;
        t[o]._max=max(t[ch]._max,t[ch+1]._max);
        t[o]._min=min(t[ch]._min,t[ch+1]._min);
    }

    接下来我们给出修改区间的函数,在这里区间重置的影响在处理懒标记的时候就处理好了,不用考虑相互作用,如果相互作用的话,难度直接爆炸

    void change(int l,int r,long long x,int o)
    {
        int ch=o*2;
        if(t[o].l==l&&t[o].r==r)
        {
            t[o].lazy+=x;
            release(o);
            return;
        }
        release(o);
        int m=(t[o].l+t[o].r)/2;
        if(r<=m)
        {
            change(l,r,x,ch);
            release(ch+1);
        }
        if(l>m)
        {
            change(l,r,x,ch+1);
            release(ch);
        }
        if(l<=m&&r>m)
        {
            change(l,m,x,ch);
            change(m+1,r,x,ch+1);
        }
        t[o].sum+=(r-l+1)*x;
        t[o]._max=max(t[ch]._max,t[ch+1]._max);
        t[o]._min=min(t[ch]._min,t[ch+1]._min);
    }

    查询区间和,查询区间最大值以及查询区间最小值大同小异

    long long query(int l,int r,int o)
    {
        int ch=o*2;
        release(o);
        if(t[o].l==l&&t[o].r==r)
            return t[o].sum;
        int m=(t[o].l+t[o].r)/2;
        if(r<=m)
            return query(l,r,ch);
        if(l>m)
            return query(l,r,ch+1);
        if(l<=m&&r>m)
            return query(l,m,ch)+query(m+1,r,ch+1);
    }
    long long get_max(int l,int r,int o)
    {
        int ch=o*2;
        release(o);
        if(t[o].l==l&&t[o].r==r)
            return t[o]._max;
        int m=(t[o].l+t[o].r)/2;
        if(r<=m)
            return get_max(l,r,ch);
        if(l>m)
            return get_max(l,r,ch+1);
        if(l<=m&&r>m)
            return max(get_max(l,m,ch),get_max(m+1,r,ch+1));
    }
    long long get_min(int l,int r,int o)
    {
        int ch=o*2;
        release(o);
        if(t[o].l==l&&t[o].r==r)
            return t[o]._min;
        int m=(t[o].l+t[o].r)/2;
        if(r<=m)
            return get_min(l,r,ch);
        if(l>m)
            return get_min(l,r,ch+1);
        if(l<=m&&r>m)
            return min(get_min(l,m,ch),get_min(m+1,r,ch+1));
    }

    所有的重置和修改都是从头一直往下改,改到对应的区间就打上懒标记,其后的实现逻辑交给释放懒标记处理,所以我们在查询的时候只要释放了懒标记,之前所有的影响都可以忽略不计

    下面给出完整的线段树模板,对于更复杂的线段树问题,将单独开文章进行描述

      1 //aininot260 区间修改,区间重置,查询区间和,查询区间最值 
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<algorithm>
      5 using namespace std;
      6 const int maxn=100005,maxq=100005;
      7 int n,q;
      8 long long a[maxn];
      9 struct tree
     10 {
     11     long long sum,lazy;
     12     long long _max,_min;
     13     bool v;
     14     int l,r;
     15 }t[4*maxn];
     16 void buildtree(int l,int r,int o)
     17 {
     18     t[o].l=l,t[o].r=r;
     19     if(t[o].l==t[o].r)
     20     {
     21         t[o].sum=t[o]._max=t[o]._min=a[l];
     22         return;
     23     }
     24     int ch=o*2;
     25     int m=(l+r)/2;
     26     buildtree(l,m,ch);
     27     buildtree(m+1,r,ch+1);
     28     t[o].sum=t[ch].sum+t[ch+1].sum;
     29     t[o]._max=max(t[ch]._max,t[ch+1]._max);
     30     t[o]._min=min(t[ch]._min,t[ch+1]._min);
     31 }
     32 void release(int o)
     33 {
     34     if(t[o].lazy==0&&t[o].v==0)
     35         return;
     36     int ch=o*2;
     37     int flag=1;
     38     if(t[o].v)
     39     {
     40         t[o].sum=(t[o].r-t[o].l+1)*t[o].lazy;
     41         t[o]._max=t[o]._min=t[o].lazy;
     42         if(t[o].l!=t[o].r)
     43         {
     44             t[ch].lazy=t[ch+1].lazy=t[o].lazy;
     45             t[ch].v=t[ch+1].v=true;
     46         }
     47         t[o].v=false;
     48         flag=0;
     49     }
     50     if(flag)
     51     {
     52         t[o].sum+=(t[o].r-t[o].l+1)*t[o].lazy;
     53         t[o]._max+=t[o].lazy;
     54         t[o]._min+=t[o].lazy;
     55         if(t[o].l!=t[o].r)
     56         {
     57             t[ch].lazy+=t[o].lazy;
     58             t[ch+1].lazy+=t[o].lazy;
     59         }
     60     }
     61     t[o].lazy=0;
     62 }
     63 void reset(int l,int r,long long x,int o)
     64 {
     65     int ch=o*2;
     66     if(t[o].l==l&&t[o].r==r)
     67     {
     68         t[o].lazy=x;
     69         t[o].v=true;
     70         release(o);
     71         return;
     72     }
     73     release(o);
     74     int m=(t[o].l+t[o].r)/2;
     75     if(r<=m)
     76     {
     77         reset(l,r,x,ch);
     78         release(ch+1);
     79     }
     80     if(l>m)
     81     {
     82         reset(l,r,x,ch+1);
     83         release(ch);
     84     }
     85     if(l<=m&&r>m)
     86     {
     87         reset(l,m,x,ch);
     88         reset(m+1,r,x,ch+1);
     89     }
     90     t[o].sum=t[ch].sum+t[ch+1].sum;
     91     t[o]._max=max(t[ch]._max,t[ch+1]._max);
     92     t[o]._min=min(t[ch]._min,t[ch+1]._min);
     93 }
     94 void change(int l,int r,long long x,int o)
     95 {
     96     int ch=o*2;
     97     if(t[o].l==l&&t[o].r==r)
     98     {
     99         t[o].lazy+=x;
    100         release(o);
    101         return;
    102     }
    103     release(o);
    104     int m=(t[o].l+t[o].r)/2;
    105     if(r<=m)
    106     {
    107         change(l,r,x,ch);
    108         release(ch+1);
    109     }
    110     if(l>m)
    111     {
    112         change(l,r,x,ch+1);
    113         release(ch);
    114     }
    115     if(l<=m&&r>m)
    116     {
    117         change(l,m,x,ch);
    118         change(m+1,r,x,ch+1);
    119     }
    120     t[o].sum+=(r-l+1)*x;
    121     t[o]._max=max(t[ch]._max,t[ch+1]._max);
    122     t[o]._min=min(t[ch]._min,t[ch+1]._min);
    123 }
    124 long long query(int l,int r,int o)
    125 {
    126     int ch=o*2;
    127     release(o);
    128     if(t[o].l==l&&t[o].r==r)
    129         return t[o].sum;
    130     int m=(t[o].l+t[o].r)/2;
    131     if(r<=m)
    132         return query(l,r,ch);
    133     if(l>m)
    134         return query(l,r,ch+1);
    135     if(l<=m&&r>m)
    136         return query(l,m,ch)+query(m+1,r,ch+1);
    137 }
    138 long long get_max(int l,int r,int o)
    139 {
    140     int ch=o*2;
    141     release(o);
    142     if(t[o].l==l&&t[o].r==r)
    143         return t[o]._max;
    144     int m=(t[o].l+t[o].r)/2;
    145     if(r<=m)
    146         return get_max(l,r,ch);
    147     if(l>m)
    148         return get_max(l,r,ch+1);
    149     if(l<=m&&r>m)
    150         return max(get_max(l,m,ch),get_max(m+1,r,ch+1));
    151 }
    152 long long get_min(int l,int r,int o)
    153 {
    154     int ch=o*2;
    155     release(o);
    156     if(t[o].l==l&&t[o].r==r)
    157         return t[o]._min;
    158     int m=(t[o].l+t[o].r)/2;
    159     if(r<=m)
    160         return get_min(l,r,ch);
    161     if(l>m)
    162         return get_min(l,r,ch+1);
    163     if(l<=m&&r>m)
    164         return min(get_min(l,m,ch),get_min(m+1,r,ch+1));
    165 }
    166 int main()
    167 {
    168     cin>>n>>q;
    169     for(int i=1;i<=n;i++)
    170         cin>>a[i];
    171     buildtree(1,n,1);
    172     while(q--)
    173     {
    174         string x;
    175         cin>>x;
    176         if(x=="add")
    177         {
    178             int y,z,w;
    179             cin>>y>>z>>w;
    180             change(y,z,w,1);
    181         }
    182         if(x=="sum")
    183         {
    184             int y,z;
    185             cin>>y>>z;
    186             cout<<query(y,z,1)<<endl;
    187         }
    188         if(x=="set")
    189         {
    190             int y,z,w;
    191             cin>>y>>z>>w;
    192             reset(y,z,w,1);
    193         }
    194         if(x=="max")
    195         {
    196             int y,z;
    197             cin>>y>>z;
    198             cout<<get_max(y,z,1)<<endl;
    199         }
    200         if(x=="min")
    201         {
    202             int y,z;
    203             cin>>y>>z;
    204             cout<<get_min(y,z,1)<<endl;
    205         }
    206     }
    207     return 0;
    208 }
  • 相关阅读:
    Java中,&&与&,||与|的区别
    Hibernate中的merge方法 以及对象的几中状态
    你希望函数的某些参数强制使用关键字参数传递:
    7.1 可接受任意数量参数的函数:
    perl urlencode
    python UnicodeDecodeError: 'utf8' codec can't decode byte 0xd6 in position 15: invalid continuation
    python 使用__slots__
    python 面向对象编程
    Python flask post接口
    python flask get传参
  • 原文地址:https://www.cnblogs.com/aininot260/p/9304936.html
Copyright © 2011-2022 走看看