学习笔记:动态开点
Yizhixiaoyun · · 个人记录
博客园
什么是动态开点
我们发现,线段树的一次操作只与一个链有关,有一些节点可能是从头到尾都用不到的。所以我们可以在建树时,不开满
例如下面这张图:
我们首先存
-
发现
2 在1-5 中,我们发现并没有这个点,那么建立。 -
发现
2 在1-3 中,我们发现并没有这个点,那么建立。 -
发现
2 在1-2 中,我们发现并没有这个点,那么建立。 -
建立点
2 。
接着存
-
发现
3 在1-5 中,我们发现已经有这个点,不进行操作。 -
发现
3 在1-3 中,我们发现已经有这个点,不进行操作。 -
建立点
3 。
以此类推。
最后我们发现,点
动态开点适用于什么问题
动态开点一般在
动态开点的基本框架
pushup
void pushup(int o){a[o].s=a[a[o].l].s+a[a[o].r].s;}
update
跟着上文的思路走。
void update(int l,int r,int dl,int dr,int v,int &o){
if(o==0) o=++cnt,a[o].tag=0;
if(dl<=l&&r<=dr){
a[o].s=v*(r-l+1);
a[o].tag=v+1;
return;
}
pushdown(l,r,o);
int mid=(l+r)>>1;
if(dl<=mid) update(l,mid,dl,dr,v,a[o].l);
if(dr>mid) update(mid+1,r,dl,dr,v,a[o].r);
pushup(o);
}
query
对于查询操作,遇到一个没有访问过的节点,直接返回。
int query(int l,int r,int x,int y,int o){
if(o==0) return 0;
if(l==x&&r==y) return c[o];
int mid=(l+r)>>1;
if(y<=mid) return query(l,mid,x,y,a[o].l);
else if(x>mid) return query(mid+1,r,x,y,a[o].r);
return query(l,mid,x,mid,a[o].l)+query(mid+1,r,mid+1,y,a[o].r);
}
实战演练
CF915E Physical Education Lessons
动态开点模板题。(当然你也可以用珂朵莉树做)