[学习笔记] 区改区查标记永久化线段树
写完树剖之后发现还没有讲过区改区查线段树。。。
标记永久化线段树的用处:
支持区改区查,嗯,就这样。(不过听很多dalao说这种线段树有利于写主席树)
算法核心思路:
对于一段区间加,假如它把线段树上的一部分完全包涵,那么我们就把它“永久”的加在这部分上,否则就加在另外一个神奇的地方,这个神奇的地方只有当询问区间将其完全包涵才能加。
这样我们就把区间加变成了log级别的。
代码实现:
procedure update(k,l,r,x,y,z:longint); var mid:longint; begin if (l>=x)and(r<=y) then begin add_sum[k]:=(add_sum[k]+z)mod p; exit; //完全包涵,把标记永久化。 end; sum[k]:=(sum[k]+(min(r,y)-max(l,x)+1)*z mod p)mod p; //加到一个神奇的地方(我们可以叫它半永久标记,好吧我瞎掰的。。。) mid:=(l+r)>>1; if x<=mid then update(k*2,l,mid,x,y,z); //像普通线段树的查询操作一样继续更新其他节点,直到需要我们修改的区间全部被永久化为止 if y>mid then update(k*2+1,mid+1,r,x,y,z); end; function query(k,l,r,x,y:longint):longint; var mid:longint; begin if (l>=x)and(r<=y) then exit((sum[k]+(r-l+1)*add_sum[k]mod p)mod p); mid:=(l+r)>>1; query:=(min(r,y)-max(l,x)+1)*add_sum[k]mod p; if x<=mid then query:=(query+query(k*2,l,mid,x,y))mod p; if y>mid then query:=(query+query(k*2+1,mid+1,r,x,y))mod p; end;