Part1
你真的以为树状数组只能止步于区修区查了吗?
实际上有这样一种特殊的最值:前缀最值查询。
代码:
struct BIT{int tr[N];inline int lowbit(int x){ return (x&(-x)); }void add(int x,int val){for(int i=x;i<=n;i+=lowbit(i))tr[i]=max(tr[i],val);}int query(int x){int ans=0;for(int i=x;i;i-=lowbit(i))ans=max(ans,tr[i]);return ans;}void clear(int x){for(int i=x;i<=n;i+=lowbit(i))tr[i]=0;}
};
这种操作被广泛用于偏序问题。
Part2
动态开点平衡树。(没想到吧)
思想就是一个节点代表一个区间,必要时拆点即可。
由于拆点之后中序遍历顺序不能改变,所以不能用 \(Treap\)。
拆点代码:
int split(int x,int k){int l=tr[x].l,r=tr[x].r;if(l==r)return x;if(k==1){int id1=newnode(l,l),id2=newnode(l+1,r);tr[tr[x].fa].ch[dir(x)]=id2,tr[id2].fa=tr[x].fa;tr[id2].ch[0]=id1,tr[id1].fa=id2;if(tr[x].ch[0])tr[tr[x].ch[0]].fa=id1,tr[id1].ch[0]=tr[x].ch[0];if(tr[x].ch[1])tr[tr[x].ch[1]].fa=id2,tr[id2].ch[1]=tr[x].ch[1];push_up(id1),se.add(rot,l,l,id1,1,M);push_up(id2),se.add(rot,l+1,r,id2,1,M);if(root==x)root=id2; return id1;}else if(k==r-l+1){int id1=newnode(l,r-1),id2=newnode(r,r);tr[tr[x].fa].ch[dir(x)]=id2,tr[id2].fa=tr[x].fa;tr[id2].ch[0]=id1,tr[id1].fa=id2;if(tr[x].ch[0])tr[tr[x].ch[0]].fa=id1,tr[id1].ch[0]=tr[x].ch[0];if(tr[x].ch[1])tr[tr[x].ch[1]].fa=id2,tr[id2].ch[1]=tr[x].ch[1];push_up(id1),se.add(rot,l,r-1,id1,1,M);push_up(id2),se.add(rot,r,r,id2,1,M);if(root==x)root=id2; return id2;}else {int id1=newnode(l,l+k-2),id2=newnode(l+k-1,l+k-1),id3=newnode(l+k,r);tr[tr[x].fa].ch[dir(x)]=id2,tr[id2].fa=tr[x].fa;tr[id2].ch[0]=id1,tr[id1].fa=id2;tr[id2].ch[1]=id3,tr[id3].fa=id2;if(tr[x].ch[0])tr[tr[x].ch[0]].fa=id1,tr[id1].ch[0]=tr[x].ch[0];if(tr[x].ch[1])tr[tr[x].ch[1]].fa=id3,tr[id3].ch[1]=tr[x].ch[1];push_up(id1),se.add(rot,l,l+k-2,id1,1,M);push_up(id3),se.add(rot,l+k,r,id3,1,M);push_up(id2),se.add(rot,l+k-1,l+k-1,id2,1,M);if(root==x)root=id2; return id2;}
}
常数略大