美高梅娱乐注册送彩金zkw线段树学笔记

图形来源于网络,侵删

Step1(建树):

先是, style=”color: #ff0000;”>堆式储存是着重。——《统计的能力》

或许不用几近说,用是zkw(重口味)的一律不胜特征,如下图:

 美高梅娱乐注册送彩金 1

同等、 style=”color: #ff0000;”>化为二进制后不难看出,叶子节点的父节点是它们的 style=”color: #ff0000;”>前缀。———>>也就是说,找大只有待 style=”color: #ff0000;”>右变一各(>>)!

仲、相反,找爸爸节点的叶子就错移————>>左移一号呢 style=”color: #ff0000;”>左儿子,再 style=”color: #ff0000;”>+1(或者 style=”color: #ff0000;”>|1)为 style=”color: #ff0000;”>右儿子

三、第n臃肿节点个数为 style=”color: #ff0000;”>2(n-1)

季、Last but not least,最底部节点个数为您 style=”color: #ff0000;”>实际最多好操作的往往的个数(换个说法,应该好称之为 style=”color: #ff0000;”>值域 style=”color: #000000;”>, style=”color: #ff0000;”>为2的次幂)。!!!( style=”color: #ff0000;”>最重要

 有了其,就得起踏上上理论化为实际的高大征途。

 实践开始!

事实上,很多上数组中数都不是2底次幂,怎么收拾?————>>直接开2的次幂就实施了,多的半空中不要了。

style=”color: #000000;”>美高梅娱乐注册送彩金 2————《统计的能力》

同、我们知晓,最底部实际上存的凡原数组,同时鉴于堆式储存的特点,序号为是顺序排列的,也就是说————>>当我们得查询或涂改时,只需要以原数组序号及丰富一个再三,设为m吧。

如何求m

for(m=1;m<n;m<<=1);

 实际上,m啊极底部所有节点的父节点总数,所以就需要而m为1,不断左移,当m>=n时停止。

对此叶子直接输入,对于父节点从叶子(继承?区间与,最酷价值,最小值……)。

build函数轻松得出:

void build(int n)
{
    for(m=1;m<n;m<<=1);
    //m<<=1;//避免查端点值出错
    for(int i=m+1;i<n+m+1;i++) scanf("%d",&a[i]);//从m+1叶子节点开始,避免查询[1,...]时出错。
    for(int i=m-1;i;--i) a[i]=a[i<<1]+a[i<<1|1];//区间和
/*
for(int i=m-1;i;--i) a[i]=max(a[i<<1],a[i<<1|1]);//最大值
for(int i=m-1;i;--i) a[i]=min(a[i<<1],a[i<<1|1]);//最小值
*/
}

【宋太祖•赵匡胤】一壹

间隔修改

 最简易的唯有区间加减(但我吧才说之),和间隔查询同一,只要以更新ans改吗a[i]+=val,加上差分回归(需用差分)。

void intervalup(int l,int r,int val)
{
    int tmp=0;
    for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) a[l^1]+=val;
        if(r&1) a[r^1]+=val;
        tmp=min(a[l],a[l^1]),a[l]-=tmp,a[l^1]-=tmp,a[l>>1]+=tmp;
        tmp=min(a[r],a[r^1]),a[r]-=tmp,a[r^1]-=tmp,a[r>>1]+=tmp;
    }
    while(l) tmp=min(a[l],a[l^1]),a[l]-=tmp,a[l^1]-=tmp,a[l>>=1]+=tmp;
}

•本篇看点:陈桥兵变。陈桥兵变在历史上一直为叫做是一个偶发。因为类似改朝换代这种大事件,一般都设通过几旗血洗厮杀才会上目的,而陈桥兵变也偏偏是透过一个黄袍加身,就吃赵匡胤把后周天下,移姓为宋,所以,陈桥兵变并无像咱来看的表象那样,普通,甚至毫不起眼,接下便深受咱们经过陈桥兵变,来重新认识一下这个手法策划陈桥兵变的腹黑老大——赵匡胤。

单点修改

首先说说单点修改。

咱们都清楚,线段树是出于上顶下遍历的,而zkw鉴于可以直接找到叶子,是由下至齐遍历的,因此避免了许多剩余的拜会,对于只有点修改,我们只有待将用修改的点找到(加上m),并循环使用至祥和、父节点直到根节点,方便了累累。

void updata(int pos,int val)
{
    a[pos+=m]+=val;
    while(pos)
    {
        a[pos>>=1]=a[pos<<1]+a[pos<<1|1];
    }
}

壹• 故事

【麻衣有言说:以严肃的神态,通俗易懂的文,来啊汝讲述那诙谐的历史。】

初一:后周显德七年,也就是是960年底初一,一如以往的新年,皇宫里热闹,而我们年就七秋之晚圆满小天王柴宗训【周恭帝】,此时刚于外年单纯二十多春秋之母符太后拉着有些手,登上朝堂,接受百官朝贺。

宴会进行到一半经常,突然产生个侍卫来报,说北方的契丹族突然南下,北汉啊还要向东方而下,两着还备出击我后到!一时间,刚刚喜庆的气氛瞬间杂乱无章起来,大臣等都慌了手脚,都扭头看向这呆的小柴宗训,小柴宗训则借助着胳膊瞪着无辜的对仗立向自己之母后符太后,符太后心想,小宗训啊,母后前一个月份还仅是只皇后啊!所以,符太后只能默默的回头求助两个借口孤大臣,也就是范质,王溥【pu】。而这有限独还快要五十春的老前辈念及周太祖郭威以及周世宗柴荣的好处,对于外族侵犯也着急上火,所以没有多加思索就赶忙叫殿前都指挥使赵匡胤出战,谁知匡胤却推脱兵少将寡,不可知出战,范质只好委以赵匡胤最高军权,可以调全国武装,赵匡胤就才勉强的应允了。【麻衣看到众多宋史丢了赵匡胤推脱出战这个细节】

初二:于是亚上,也就是正月初二,赵匡胤就先派副都点检慕容延钊作为先锋出发了。但是都就是于此时,无缘无故的开端疯狂传一模一样段落流言,将因出军之日,策点检为天子。——《续资治通鉴长编》。

初三:正月初二就这么干巴巴的千古矣,到了第三上,也不怕是正月初三,赵匡胤就才带在滚滚的枪杆子出发了。但是,这个时刻,部队里吧起无端的痴传一模一样段落流言,据说是一个会面夜观天象之老道说之,天生又起同天,黑光摩荡者久的。——《宋史》卷——《太祖本纪》【记忆还生个野史记载赵匡胤因城里的流言而不敢出兵,但结尾让那个胞妹用在抹面杖敲起,这才出战,真不真正不掌握,麻衣在此处不得不做到完美

这些种种流言的意思只是就是是,老天爷要叫殿前犹点检做皇帝,所以,正月初三的晚上,赵匡胤一行来到陈桥驿站休息之上,也不晓凡是何人将领起底腔,说,咱们在外地征战沙场,累先不说,就说现在丢失主年幼,万一异长大了忘了咱功劳怎么处置,不如我们趁少主刚刚登基,还人心不妥当时,赶紧拥戴点检赵匡胤也上,说不定到时刻还能及时什么好素养啊。

众将领一听,心里还惦记,这人说之产生道理啊,所以,一博口立即高兴之去探寻赵匡胤了,但是刚刚到赵匡胤的帷幕外,就于谋士赵普【后来当了北宋的宰相】和赵匡胤的兄弟赵匡义拦住了,赵普问明来意后,就说了一定量句子话,第一,赵匡胤不自然会容许反叛。【太尉赤忠,必不汝赦——《续资质通鉴长编》】。第二,赵匡胤绝对忠于后周,而且若他理解这宗事,他不仅不倒,而且还免会见赦免你们。

赵普这样一说,底下有一对丁退了,然后赵普接着劝,说是谋逆皇位这种事,一旦说说话,后果就会见好要紧,因为若说讲时就是犯了谋逆之罪,但是若你走了都成了,说不定就是于罪臣变成功臣了。赵普的一席话,把这些将们唬的相同发呆一发呆的,然后用所有武将们点头,齐声高呼,立点检为天王!立点检为天王时,赵普在内心乐了。

继之赵普挥了挥手,示意将领们住,自个就说到,大伙儿现在可去寻觅点检查,但是,鄙人还产生一个求,那就算是央各位将领严管手下武装,反叛时无克抢走烧杀,要包首都底安,因为都如若乱了,周围城区势必为会见跟着乱。众将领点头想想,也是,反叛这种大事,应该谨慎点,所以都绞尽脑汁开始自发安排了,最后是这样的,一拨人先失追寻赵匡胤,另一样转人先行去保护赵匡胤于开封的骨肉,捎带通知守卫城门的卫队高官,也就算是赵匡胤的好哥们儿,石守信,王审琦等,告诉他们赵匡胤要反了。

马上边都的行安顿好后,那边赵匡义【后也避讳改也赵光义】先喝醒了哥哥赵匡胤,然后酒醒矣之赵匡胤只见突然身边多了不少老公,以及男人手中亮晃晃的刀子,然后不知情凡是哪位男人用在一个粗的黄袍就朝着赵匡胤身上学,然后其他人就跪下,喊万秋万秋万万东。那么,赵匡胤什么影响吗?【固拒之——《续资治通鉴长编》】,可是赵匡胤越拒绝,这些将就愈加设受他当,所以,最后赵匡胤不得不勉为其难的铮铮了之上。【有些历史版本省略了赵普赵光义这环节,再有的本子说是赵普赵光义石守信王审琦李处耘在初三这天因听说了参谋苗训的观赛天象说晚,聚在同讨论,直到正月初四朝,才拥立赵匡胤为帝。甚至还发野史记载,赵匡胤提前将母亲藏于寺庙里了。】麻衣在马上说之实事,一切以续资治通鉴长编为仍。

初四:交了正月初四就同上,赵匡胤先叫了潘美【很红的潘美,暂且不论】去都告诉,当时文明百官和小皇帝柴宗训都当探讨,潘美这样一游说,群臣开始大呼小叫了,只见范质握在王溥的手,说,“急促遣将,吾辈之罪为”——《续资治通鉴长编》。史书上还来只写是场面的底细,“爪入溥手,几来血”——《续资治通鉴长编》

赵匡胤反叛的消息,一时间拿朝堂的君臣们来的毛,当时除范质王溥的感应,就独自出一个专程之,韩通!韩通是中央禁军的一个领袖,当时韩通准备组织部下负隅顽抗,不料也叫赵匡胤的部属王彦升拦截停了,灭了全门!【之后王彦升也为此交到了代价】。接下来就是赵匡胤骑马从东门迈进了都城,注意!在进城前,赵匡胤同战士们召开了只协定,也不怕是,一不可知凌辱太后以及小皇帝,二未能够伤当为大臣,三勿许伤及人民【不可知烧杀抢掠】,谁要是发了,灭三族!说罢这些,赵匡胤就进城了,接下就禅位登基,当时一个后周底翰林学士陶谷已写好了,至于怎么形容好的,史书并未记载。

终极就改元,将继周显德七年,改也建隆元年,且以朝改吗宋【因为之前赵匡胤是于宋州当节度使的】,之后赵匡胤就从头大赦天下了,不仅拿后圆满小天子柴宗训封为郑王,而且事先后周的鼎,在后周是当什么官的,在宋朝即令跟着当什么官。

故事到马上,基本上陈桥兵变就到底讲述了了。【因篇幅有限,麻衣会特地增加一个稍稍链接,专门进行陈桥兵变的文章】

Total:

zkw线段树

1.建树非常简单。

2.丝段树能干的,它还实施。(似乎是这般的)

3.重新多惊喜等您来打通……

贰•分析

PS:

说从线段树,可谓是平拿辛酸泪(尽管自己欣赏打树状数组??)。代码较?(似乎是滴),TLE(屡见不鲜),递归建树(!!!),说实在,用(说到底lowbit差了些,你懂的)。

先行来平等犯线段树:

 

#include<iostream>
#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int maxn=2e4;
int segtree[maxn*4+10],array[maxn];
void build(int,int,int);
int query(int,int,int,int,int);
void updata(int,int,int,int,int);
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&array[i]);
    }
    build(1,1,n);
    ……………………
    return 0;
}
void build(int node,int begin,int end)//node结点,begin为array某子区间首标号,end为某子区间末标号。
{
    if(begin==end)
    {
        segtree[node]=array[begin];//首末相等,直接赋值。
    }
    else
    {
        build(2*node,begin,(begin+end)>>1);//区间长度不为一,左右递归。
        build(2*node,(begin+end)>>1+1,end);
        /*---------------区间min------------*/
        if(segtree[2*node]<=segtree[2*node+1])//max改为?>=?
        {
            segtree[node]=segtree[2*node];
        }
        else
        {
            segtree[node]=segtree[2*node+1];
        }
        /*-------------------------------*/

        /*---------------区间和------------*/
        segtree[node]=(segtree[2*node]+segtree[2*node+1]);
        /*---------------------------*/
    }
}
int query(int node,int begin,int end,int left,int right)
{
    int p1,p2;
    if(left>end||right<begin)
    {
        return -1;
    }
    if(left<=end&&right>=begin)
    {
        return segtree[node];
    }
    p1=query(2*node,begin,(begin+end)>>1,left,right);
    p2=query(2*node+1,(begin+end)>>1+1,end,left,right);
    if(p1==-1)
    {
        return p2;
    }
    if(p2==-1)
    {
        return p1;
    }
    if(p1<=p2)
    {
        return p1;
    }
    else
    {
        return p2;
    }
}
void updata(int node,int begin,int end,int pos,int val)
{
    if(begin==end)
    {
        segtree[node]+=val;
        return;
    }
    int m=(left+right)>>1+1;
    if(pos<=m)
        updata(2*node,begin,(begin+end)>>1,pos,val);
    else
        updata(2*node+1,(begin+end)>>1+1,end,pos,val);
    /*----MIN--*/
    segtree[node]=min(segtree[2*node],segtree[2*node+1]);
    /*---------*/
}

 真长(还并未写了)!!!

当自身当近年来,看到了zkw(不要误会),本身之世界豁然开朗,代码天皇荣耀归来,多年守望简洁先锋,终于get到zkw神器。(实际上我不过玩MC)

 zkw(张昆玮大神):男,身处清华大学。zkw线段树出自《统计的能力》。

•⑴赵匡胤布局篇:

即怎么看还当是赵匡胤被动当的统治者,其实不然,直到现在很多史学家都想是赵匡胤一手策划的陈桥兵变,至于因,麻衣在后的小链接上发。我们现在首要来探讨一下,陈桥兵变的布局。

气候占举足轻重位置。为就周世宗柴荣,才刚好去世一个月份,而初登基的散失主柴宗训则还未成年懵懂,至于年轻的符太后,两独年快半百的宰相,也都自免了差不多特别的企图。所以,朝廷中一时多少混乱。

接下来反对者次的。咱更来探,如果赵匡胤要当上,谁会反对。首先是范质,王溥两位首相,因为周太祖郭威以及周世宗柴荣对她们来恩,接下去便是韩通【和赵匡胤同,都控制兵权,不过韩通这个人口死效忠后圆满】,慕容延钊【这个人于独特,虽然属于赵匡胤部下,但是对后周忠心耿耿】,除了这几乎独人,其他的要么都是墙头草,要么现在都非以首都。

异常好,反对者分析了了。接下来,当然就是是运气,民心了。因为当时的封建社会,人们都比较信仰老天爷,一般谋逆这种事情,如果无让国民信服,那么这个上大可能就会见坐及骂名。其次,宋朝在五代十国大动乱的底,因为老是发生乱,今天夫当国王,明天以此当皇上,不仅士兵们本着将没有诚意意识,连老百姓对部队,也从不另外信任感。

综合所述,赵匡胤的启幕布局,已经以脑海形成了。

•⑵赵匡胤布局值得咱们借鉴篇

【麻衣有说话说:很多总人口一直纠结历史到底真不真实是题目,其实很简短,麻衣就想问问,你知不知道成龙有几只私生子,所以,历史的存并无是受丁去花心思弄通透它,而是通过它,能够让咱得到有更,教训。】

第一是,赵匡胤如何调整将士们,自发的,心甘情愿的尾随他兵变。随即点,管理者应该好借鉴,很多时节,管理者会为了什么给职工全力以赴听命于自己假如抑郁,看看赵匡胤就知了,一句话,员工的利益,自己领悟。

从就是是赵匡胤如何管理这些将士们,也不怕是规章制度。平等无能够凌辱小天子有些太后,二未可知损害当于大臣,三勿能够伤无辜公民,如产生犯者,灭三族!纵观历史上的旁兵变,大都血腥残暴,而赵匡胤制定铁的制度,不仅体现出他生性宅心仁厚,对待皇帝或者平民,都好爱护每一个命。还反映出他知道一个精美的组织去不上马一个以人口啊本之社会制度。

末尾,因篇幅有限,麻衣在近期用会见将陈桥兵变的拓展,笔记,以及对陈桥兵变的另类质疑,通过另外一个小链接发出来,贴在文章外,供大家参考。我是麻衣,我好到认真。

单点查询

单点a[q]?直接查[q,q]勿就行了呗。对,这是从来不错。但咱若将它们换得复杂一些(并无是抓笑,说实在的,谁愿意写长篇大论的code),这是为着RMQ做准备,这是我们需要一个神奇的物——差分,把子节点所抱的值维护为与该父节点的差值。

 所以,build函数需要改:

void build(int n)//区间和
{
    for(;m<n;m<<=1);
    //m<<=1;//避免查端点值出错
    for(int i=m+1;i<n+m+1;i++) scanf("%d",&a[i]);//从m+1叶子节点开始,避免查询[1,...]时出错。
    for(int i=m-1;i;--i) 
    {
        a[i]=min(a[i<<1],a[i<<1|1]);
        a[i<<1]-=a[i],a[i<<1|1]-=a[i];
    }
}

 

这会儿底询问,只待由叶子节点不断循环加上父节点直到根节点。

 

int point(int x)
{
    int ans=0;
    while(x) 
    {
        ans+=a[x],x>>=1;
    }
    return ans;
}

Last:

 以上就是zkw的极度基本内容,简单也非略,最后,来同样串zkw类

//powered by:spaceskynet 2017-03-06
const int maxn=1e5;
class zkw
{
public:
    zkw()
    {
        m=1;
    }
    void build(int n)//区间和
    {
        for(;m<n;m<<=1);
        //m<<=1;//避免查端点值出错
        for(int i=m+1;i<n+m+1;i++) scanf("%d",&a[i]);//从m+1叶子节点开始,避免查询[1,...]时出错。
        for(int i=m-1;i;--i) a[i]=a[i<<1]+a[i<<1|1];
        /**差分建树
        for(int i=m-1;i;--i)
        {
            a[i]=min(a[i<<1],a[i<<1|1]);
            a[i<<1]-=a[i],a[i<<1|1]-=a[i];
        }
        **/
    }
    int query(int l,int r)
    {
        int ans=0;
        for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) ans+=a[l^1];
            if(r&1) ans+=a[r^1];
        }
        /************
        int mid=max(l,r);
        while(mid)
        {
            ans+=a[mid>>=1];//差分时定要记住回归,不要只将差值max输出
        }
        *************/
        return ans;
    }
    void updata(int pos,int val)
    {
        a[pos+=m]+=val;
        while(pos)
        {
            a[pos>>=1]=a[pos<<1]+a[pos<<1|1];
        }
    }
    void intervalup(int l,int r,int val)
    {
        int tmp=0;
        for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) a[l^1]+=val;
            if(r&1) a[r^1]+=val;
            tmp=min(a[l],a[l^1]),a[l]-=tmp,a[l^1]-=tmp,a[l>>1]+=tmp;
            tmp=min(a[r],a[r^1]),a[r]-=tmp,a[r^1]-=tmp,a[r>>1]+=tmp;
        }
        while(l) tmp=min(a[l],a[l^1]),a[l]-=tmp,a[l^1]-=tmp,a[l>>=1]+=tmp;
    }
    int point(int x)//差分单点查询
    {
        int ans=0;
        while(x) 
        {
            ans+=a[x],x>>=1;
        }
        return ans;
    }
private:
    int a[2*maxn+2],m;
};

 

Step2(操作):

 线段树最经典(也就是是咱为何用如此……的线树)的虽是询问修改操作了,时间复杂度比较平均,都也O(logn)。

区间查询 

查询区间和,暂且设间隔也[l,r]吧,zkw又同样特色,化为(l-1,r+1)开区内计。

于是,这虽是怎输入时一旦从m+1开始,避免查询[1,…]时常错,若一旦查询[0,……],下标需加上1。

int query(int l,int r)
{
    int ans=0;
    for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) ans+=a[l^1];
        if(r&1) ans+=a[r^1];
    }
    return ans;
}

 ~l&1,意思是是否为小子,对于兄弟节点的话,最低位为0或1,0为左儿子,1为右儿子,对于左端点
l来说,我们无非待往右侧合并更新ans(加上兄弟节点,也尽管是右手节点,l^1),而不任那左手。

r&1,同理,意思是是否为儿子。

每次循环后转移向那个父节点继续操作,出口也l^r^1,为什么?若lr切莫也与一些或兄弟节点,l^r^1一定为true,否则在啊跟一些要么兄弟节点时跳出循环。

求max

用更新时+改为max就行了。

int query(int l,int r)
{
    int ans=0;
    for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) ans=max(a[l^1],ans);
        if(r&1) ans=max(a[r^1],ans);
    }
    /************
    int mid=max(l,r);
    while(mid)
    {
        ans+=a[mid>>=1];//差分时定要记住回归,不要只将差值max输出
    }
    *************/
    return ans;
}

求min

将上述max改为min

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website