ZKW线段树之旅(1)

来源:互联网 发布:c excel重复数据删除 编辑:程序博客网 时间:2024/06/02 05:53

膜拜ZKW神犇。。。。Orz。。。

ZKW线段树的思想是直接找到一个大区间对应的小区间
由于是自底向上的,所以常数很小(《统计的力量》)
其实我觉得,真正难写 的是区间修改

比如现在造一颗线段树,支持区间求和,区间修改
ZKW线段树有两种做法:
一是维护神奇 的前缀和的前缀和
二是沿用递归版线段树的思路,在 区间上打标记,然后统计

太弱,第一种不会。。。于是我就用第二种吧
区间修改:简单,就在区间上打个标记,顺便更新一下遍历到的区间和,最后当l和r父亲相同时,循环结束,再把他们的父亲们的和更新。
区间求和:先是记一下左边右边 的区间里有几个元素要加,每次就根据遍历到的区间的标记更新答案。最后当l和r父亲相同时,循环结束,再把他们的父亲们的标记拿来更新答案

好像有点大话连篇。。。上代码好了

const int maxn=262144;int sumv[maxn],addv[maxn],m;//sumv 维护区间的和,addv是标记;m不说了吧,地球人都知道void update(int l,int r,int a){    l+=m-1,r+=m+1;    int ln=0,rn=0;//记录l,r遍历到了几个元素    int s=1;//记录这一层的区间有几个元素    for(;l^r^1;l>>=1,r>>=1,s<<=1){        if(ln)sumv[l]+=ln*a;        if(rn)sumv[r]+=rn*a;        if(~l&1)addv[l^1]+=a,ln+=s;//只更新标记啊        if(r&1)addv[r^1]+=a,rn+=s;    }    data[l]+=ln*a;data[r]+=rn*a;    for(ln+=rn,l>>=1;l;l>>=1)        data[l]+=ln*a;//我的父亲们~}int query(int l,int r){    l+=m-1,r+=m+1;    int sum=0;    int ln=0,rn=0;    for(int s=1;l^r^1;l>>=1,r>>=1,s<<=1){        if(ln)sum+=addv[l]*ln;//根据标记更新和        if(rn)sum+=addv[r]*rn;        if(~l&1)sum+=data[l^1]+addv[l^1]*s,ln+=s;        if(r&1)sum+=data[r^1]+addv[r^1]*s,rn+=s;    }    sum+=addv[l]*ln+addv[r]*rn;    for(ln+=rn,l>>=1;l;l>>=1)        sum+=addv[l]*ln;//我的父亲们~    return sum;}//PS:有错误就说一说啊。。。


现在,某人又要求造一颗线段树支持 区间修改,区间最小值
还是沿用区间求和的思路,只是代码有点不同
对于更新最小值的操作,不能单纯的加减了,而是要根据儿子的值而修改。

const int maxn=262144;int data[maxn],addv[maxn],m,n;//data是区间最小int query(int l,int r){    int lmax=INT_MAX,rmax=INT_MAX;    int s=l+m-1,t=r+m+1;    bool _l=false,_r=false;    //叶节点不能通过儿子更新,判断是否可以更新    //其实好像下面有更好的判断方式。。。懒得改了    for(;s^t^1;s>>=1,t>>=1){        if(_l)lmax+=addv[s];        if(_r)rmax+=addv[t];        if(~s&1)lmax=min(lmax,data[s^1]+addv[s^1]),_l=true;        if(t&1)rmax=min(rmax,data[t^1]+addv[t^1]),_r=true;    }    lmax+=addv[s];rmax+=addv[t];    lmax=min(lmax,rmax);    for(s>>=1;s;s>>=1)lmax+=addv[s];    return lmax;}void add(int l,int r,int a){    int s=l+m-1,t=r+m+1;    for(;s^t^1;s>>=1,t>>=1){            if(s<l+m-1)data[s]=min(data[s<<1]+addv[s<<1],data[s<<1|1]+addv[s<<1|1]);                    if(t<r+m+1)data[t]=min(data[t<<1]+addv[t<<1],data[t<<1|1]+addv[t<<1|1]);            if(~s&1)addv[s^1]+=a;            if(t&1)addv[t^1]+=a;        }        data[t]=min(data[t<<1]+addv[t<<1],data[t<<1|1]+addv[t<<1|1]);        for(;s;s>>=1)            data[s]=min(data[s<<1]+addv[s<<1],data[s<<1|1]+addv[s<<1|1]);    }


嘿嘿嘿。。。
我的线段树~

0 0
原创粉丝点击