ZKW线段树
zkw线段树的特点
·代码短(可手撸)
·常数小
·空间小
原理
与普通线段树不同,zkw线段树是基于满二叉树,自底而上
区间如下图所示
查询时,先将闭区间转化为开区间,再不断移动到父亲节点的过程中,将其包含的兄弟节点进行处理,右边界处理右兄弟,左节点处理左兄弟,直到左右区间为兄弟节点
实现
建树:首先找到单元素所在的层数M,并将当前层数的值初始化。M既是层数,也是当前层数的最大个数,也是前面位置的总数(到这一层0点为止)
for(M=1;M<=n;M<<=1);
for(int i=1;i<=M<<1;i++)
T[i]=0;//T[i]=inf;
添点及单点修改,添加点从位置1开始添加
void modify(int n,int v)//单点加减/修改
{
for(T[n+=M]+=v,n>>=1;n;n>>=1) /*T[n+M]=v*/
T[n]=T[n+n]+T[n+n+1];
}
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
modify(i,x);
}
查询
1、查询区间和
ll query(int l, int r)
{
ll ans=0;
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
{
if(~l & 1) ans+=T[l^1];
if(r & 1) ans+=T[r^1];
}
return ans;
}
2、查询区间最大值//最小值同理
ll query(int l, int r)
{
ll ans=-inf;
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
{
if(~l & 1) ans=max(ans,T[l^1]);
if(r & 1) ans=max(ans,T[r^1]);
}
return ans;
}
单点查询+区间修改
这里虽然是区间修改,但因为单点查询时,会找到父亲节点所有之前加的值,不会漏算。所以就不用lazy了~
void add(int l,int r,int v)//区间加减
{
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
{
if(~l & 1) T[l^1]+=v;
if(r & 1) T[r^1]+=v;
}
}
ll query(int n)//单点查询
{
ll ans=0;
for(n+=M;n;n>>=1) ans+=T[n];
return ans;
}
区间修改+区间查询(要用lazy标记!)
不用lazy标记会出现漏加的情况,所以用lazy标记修改到根,查询到根。
void add(int L,int R,int v)//区间修改
{
L+=M-1,R+=M+1;
for(int l=L,r=R;l^r^1;l>>=1,r>>=1)
{
if(~l & 1) lazy[l^1]+=v,T[l^1]+=v;
if(r & 1) lazy[r^1]+=v,T[r^1]+=v;
}
for(int l=L>>1,r=R>>1;l;l>>=1,r>>=1)
{
T[l]=max(T[l+l],T[l+l+1])+lazy[l];
T[r]=max(T[r+r],T[r+r+1])+lazy[r];
}
}
int query(int l, int r)//区间查询
{
int lmax=-inf,rmax=-inf;
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
{
if(lazy[l]&&lmax!=-inf) lmax+=lazy[l];
if(lazy[r]&&rmax!=-inf) rmax+=lazy[r];
if(~l & 1) lmax=max(lmax,T[l^1]);
if(r & 1) rmax=max(rmax,T[r^1]);
}
for(;l;l>>=1,r>>=1)
{
lmax+=lazy[l],rmax+=lazy[r];
}
return max(lmax,rmax);
}
区间覆盖+区间查询
(暂时没看懂……)
void modify(int L,int R,int v)//区间覆盖
{
L+=M-1,R+=M+1;
for(int i=(log(M)/log(2))+1,l,r;i;i--)//log(M)/log(2))+1为当前层数
{
l=L>>i,r=R>>i;
if(lazy[l])
{
lazy[l+l]=lazy[l+l+1]=lazy[l];
T[l+l]=T[l+l+1]=lazy[l]*(1<<(i-1));
lazy[l]=0;
}
if(lazy[r])
{
lazy[r+r]=lazy[r+r+1]=lazy[r];
T[r+r]=T[r+r+1]=lazy[r]*(1<<(i-1));
lazy[r]=0;
}
}
for(int l=L,r=R,num=1;l>1;l>>=1,r>>=1,num<<=1)
{
if((l^r^1)>1)
{
if(~l & 1) lazy[l^1]=v,T[l^1]=v*num;
if(r & 1) lazy[r^1]=v,T[r^1]=v*num;
}
T[l>>1]=T[l]+T[l^1];
T[r>>1]=T[r]+T[r^1];
}
}
int query(int l, int r)
{
int ansl=0,ansr=0,ln=0,rn=0,nn=1;
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1,nn<<=1)
{
if(lazy[l]) ansl=lazy[l]*ln;
if(lazy[r]) ansr=lazy[r]*rn;
if(~l & 1) ansl+=T[l^1],ln+=nn;
if(r & 1) ansr+=T[r^1],rn+=nn;
}
for(;l;l>>=1,r>>=1)
{
if(lazy[l]) ansl=lazy[l]*ln;
if(lazy[r]) ansr=lazy[r]*rn;
}
return ansl+ansr;
}