线段树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树相关的知识,希望对你有一定的参考价值。

  线段树,顾名思义,是一种可以以log2n的时间复杂度来进行区间访问和区间查询求和的骚包操作,不同于一般的N或者是N2的算法,特点就是快,由于二叉树的性质,所以可以用位运算优化的一种裸的基础的简单数据结构。由于二叉树的性质,兴许是满的?总之左儿子是其父亲的两倍,右儿子是其父亲的两倍加一,所以更新父亲的区间操作可以写成:tree[o] = tree[o<<1] + tree[o<<1|1]; 

  那么首先,有两种操作,一种是在建树的时候,当到叶子节点的时候再读入,或者是直接读入到arr[i]中,当建树建到叶子节点的时候,把arr[o]赋值给当前tree[o]。那么怎么建树呢?

void pushup(int o){tree[o]=tree[o<<1]+tree[o<<1|1];}
void build(int o,int L,int R)
{
    if(L==R){
        tree[o]=arr[L];//也可以写成: scanf("%d",&tree[o]); 
        return ;
    }
    int M = (L+R)>>1;
    build(int o<<1,L,M);
    build(int o<<1|1,M+1,R);
    pushup(o);
}

 

因为建树(build)过程中只更新了儿子节点,所以要有一个pushup操作,目的就是为了更新祖先节点的值。

那么就可以分段处理了,比如如果要单点修改就要用update了

单点修改:

void update(int o,int L,int R,int x,int val)
{
    if(L==R){//找到了要修改的值 
        tree[o]+=val;
        return ;
    }
    int M = (L+R)<<1;
    if(x>M) update(o<<1|1,M+1,R,x,val);//如果要修改的点在左右端点的右边的话,那就是要更新左端点的值,并且当前标号o也要做相应的变换 
    else update(o<<1,L,M,x,val);
    pushup(o);//因为叶子节点的值有更新,所以祖先节点还是有改变。 
}

 

区间求和:

int query(int o,int L,int R,int ql,int qr)
{
    if(ql>=L&&R>=qr) return tree[o];//找到叶子节点,把叶子节点的值加入所求的ret中。 
    int M = (L+R)>>1;
    int ret = 0 ;
    if(ql >= M) ret += query(o<<1,L,M,ql,qr);//往左边找 
    if(ql < M) ret += query(o<<1|1,M+1,R,ql,qr);//往右 
    return ret ;//返回和  
}

 

区间修改:

void pushdown(int o,int L,int R)
{
    if(L==R) {
        tree[o] += lazy[o];//到达叶子节点,没法分配任务就把总值更新了 
        return ;
    }
    lazy[o<<1] += lazy[o];//把任务分配给自己的左右儿子 
    lazy[o<<1|1] += lazy[o];
    lazy[o] = 0 ;//任务分配完自己清零 
}
void update(int o,int L,int R,int ql ,int qr,int val)
{
    if(L==R){
        tree[o] += val ;
        return ;
    }
    pushdown(o,L,R);// 先往下传标记 
    int M=(L+R)>>1;
    if(ql<=M) update(o<<1,L,M,ql,qr,val);//改左边 
    if(qr>M) update(o<<1|1,M+1,R,ql,qr,val);//改右边 
    return ;
}

 

最后一个,区间求和+区间修改,在用正常区间修改的方法,也就是用下传标志的方法求和,与一般的区间求和不同的是,pushup改变了,其父亲tree[o]+=tree[o<<1]*lazy[o<<1]*(M-L+1)+tree[o<<1|1]*lazy[o<<1|1]*(R-M)

那么就可以上codevs上做题啦

1080 线段树练习

1081 线段树练习2

1082 线段树练习3

1954 线段树

4919 线段树练习4

5037 线段树练习4加强版

4927 线段树练习5

HDU 上也有很多题可以做啦

HDU 1166 敌兵布阵

HDU 1754  I Hate It

HDU 1394 Minimum Inversion Number

HDU 2795 Billboard

HDU 1698 Just a Hook

HDU 3308 LCIS

HDU 3397 Sequence operation

HDU 2871 Memory Control

HDU 1540 Tunnel Warfare

HDU 1542 Atlantis

HDU 1828 Picture

HDU 3265 Posters

HDU 3642 Get The Treasury

HDU 3954 Level up

HDU 4027 Can you answer these queries?

HDU 3333 Turing Tree

HDU 3874 Necklace

HDU 3016 Man Down

HDU 3340 Rain in ACStar

那就祝大家暑假玩的开心?

7.15清北见。

 

 

 还有93天初赛, 还有121天复赛。

那是我愿意付诸一生的人,往日不再重来。 

以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

线段树合并

数据结构——线段树

论线段树:二

线段树