(板子)平衡树维护序列
爆改了之前文艺平衡树的板子。
大致题意:
维护数列,支持 插入、删除、区间翻转、区间覆盖、区间求和、区间最大子段和。
code: (头文件等略)
const int maxn=200010,inf=2147483647;
int n,m,tot,rt;
int reuse[maxn],top;//这题有删除,所以搞了个结点回收(尝试用手写栈卡常)
struct node
{
int l,r,val,key,siz;//平衡树的基本信息
int cov,rev;//标记
int sum,lans,rans,ans;//维护的答案
//ans维护最后的区间最大子段和,可能为负;但lans和rans是可以不取的,最小为0
}tree[maxn];
inline void newnode(int &x,int val)
{
if(top)x=reuse[top--];//如果栈里有可用的结点,就先用栈里的
else x=++tot;
tree[x]=(node)
{
0,0,val,rand(),1,\
inf,0,\
val,max(val,0ll),max(val,0ll),val\
};//与上面node结构体里的对应起来
}
inline void pushup(int x)//可以参考GSS3. 注意平衡树是将左子树,右子树和结点三部分合起来,并且可能有左右子树不存在的情况
{
int lson=tree[x].l,rson=tree[x].r;
tree[x].siz=tree[lson].siz+tree[rson].siz+1;
tree[x].sum=tree[lson].sum+tree[rson].sum+tree[x].val;
tree[x].lans=max(tree[lson].lans,max(0ll,tree[lson].sum+tree[x].val+tree[rson].lans));
tree[x].rans=max(tree[rson].rans,max(0ll,tree[rson].sum+tree[x].val+tree[lson].rans));
tree[x].ans=tree[lson].rans+tree[rson].lans+tree[x].val;
if(lson)tree[x].ans=max(tree[x].ans,tree[lson].ans);
if(rson)tree[x].ans=max(tree[x].ans,tree[rson].ans);
}
inline void pushrev(int x)
{
swap(tree[x].l,tree[x].r);
swap(tree[x].lans,tree[x].rans);//别忘了把这个也给翻转一下
tree[x].rev^=1;
}
inline void pushcover(int x,int k)
{
tree[x].val=tree[x].cov=k;
tree[x].sum=tree[x].siz*k;
tree[x].lans=tree[x].rans=max(0ll,tree[x].sum);
tree[x].ans=max(k,tree[x].sum);//防止k为负
}
inline void pushdown(int x)
{
if(tree[x].cov!=inf)
{
if(tree[x].l)pushcover(tree[x].l,tree[x].cov);
if(tree[x].r)pushcover(tree[x].r,tree[x].cov);
tree[x].cov=inf;
}
if(tree[x].rev)
{
if(tree[x].l)pushrev(tree[x].l);
if(tree[x].r)pushrev(tree[x].r);
tree[x].rev=0;
}
}
inline void split(int x,int siz,int &rx,int &ry)
{
if(!x){rx=ry=0;return;}
pushdown(x);
if(tree[tree[x].l].siz<siz)
{
rx=x;
split(tree[x].r,siz-tree[tree[x].l].siz-1,tree[x].r,ry);
}
else
{
ry=x;
split(tree[x].l,siz,rx,tree[x].l);
}
pushup(x);
}
inline int merge(int x,int y)
{
pushdown(x);pushdown(y);
if(!x||!y)return x+y;
if(tree[x].key<tree[y].key)
{
tree[x].r=merge(tree[x].r,y);
pushup(x);return x;
}
else
{
tree[y].l=merge(x,tree[y].l);
pushup(y);return y;
}
}
int build(int l,int r)//一次插入多个结点用类似线段树建树的方式来优化复杂度
//要不然会被NOI那道维护数列的离谱插入次数卡爆
{
if(l==r)
{
int now,val;cin >> val;
newnode(now,val);
return now;
}
int mid=(l+r)>>1;
int x=build(l,mid),y=build(mid+1,r);
return merge(x,y);
}
void recycle(int x)//结点回收
{
reuse.push(x);
if(tree[x].l)recycle(tree[x].l);
if(tree[x].r)recycle(tree[x].r);
}
inline void del(int l,int r)//区间删除不需要一个一个删
{
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
recycle(y);//但是结点回收还是会把整个区间遍历一遍。
rt=merge(x,z);
}
inline void modify_rev(int l,int r)
{
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
pushrev(y);
rt=merge(merge(x,y),z);
}
inline void modify_cov(int l,int r,int k)
{
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
pushcover(y,k);
rt=merge(merge(x,y),z);
}
inline int query_sum(int l,int r)
{
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
int now=tree[y].sum;
rt=merge(merge(x,y),z);
return now;
}
inline int query_ans(int l,int r)
{
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
int now=tree[y].ans;
rt=merge(merge(x,y),z);
return now;
}
注意build函数的用法:
一开始读入数组中的n个数直接 rt=build(1,n);
即可
在pos之后连续插入t个数应该这样写:
int x,y;split(rt,pos,x,y);
rt=merge(merge(x,build(pos,pos+t-1)),y);