Trick——数据结构
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;
}
}
常数略大

浙公网安备 33010602011771号