【笔记】线段树优化建图
作者:互联网
实际上就是利用了线段树结构将区间表示成 logN 个节点的性质,若与某个区间连同一个权值的边,做成连到对应线段树的节点上去
例题 CF786B Legacy
考虑建两个线段树,一个父亲到儿子连单向零边,一个儿子到父亲连单向零边。单点到区间连单向边的含义:单点可以从该区间向下走直到所包含的单点;区间向单点连单向边的含义:该区间包含的单点可以向上走再到该单点。
实现细节:多开一个 1~N 的单点,和两个线段树的底层分别连无向零边,而对单点间的连边和其他一些操作就在这个上面做。另外动态开点,记录 ls 和 rs 。
部分
void build1(int x, int l, int r)
{
if (l==r) { adde(l, x, 0, ++tote), adde(x, l, 0, ++tote); }
else {
int mid = (l + r) >> 1;
ls[x] = ++totn, adde(x, ls[x], 0, ++tote);
build1(ls[x], l, mid);
rs[x] = ++totn, adde(x, rs[x], 0, ++tote);
build1(rs[x], mid+1, r);
}
}
void build2(int x, int l, int r)
{
if (l==r) { adde(l, x, 0, ++tote), adde(x, l, 0, ++tote); }
else {
int mid = (l + r) >> 1;
ls[x] = ++totn, adde(ls[x], x, 0, ++tote);
build2(ls[x], l, mid);
rs[x] = ++totn, adde(rs[x], x, 0, ++tote);
build2(rs[x], mid+1, r);
}
}
void change1(int x, int l, int r, int _l, int _r, int u, int w)
{
if (l>=_l&&r<=_r) { adde(u, x, w, ++tote); }
else {
int mid = (l + r) >> 1;
if (mid>=_l) change1(ls[x], l, mid, _l, _r, u, w);
if (mid< _r) change1(rs[x], mid+1, r, _l, _r, u, w);
}
}
void change2(int x, int l, int r, int _l, int _r, int u, int w)
{
if (l>=_l&&r<=_r) { adde(x, u, w, ++tote); }
else {
int mid = (l + r) >> 1;
if (mid>=_l) change2(ls[x], l, mid, _l, _r, u, w);
if (mid< _r) change2(rs[x], mid+1, r, _l, _r, u, w);
}
}
以及
s1 = totn = N + 1, build1(s1, 1, N);
s2 = ++totn, build2(s2, 1, N);
...
adde(u, v, w, ++tote);
change1(s1, 1, N, l, r, u, w);
change2(s2, 1, N, l, r, u, w);
...
标签:tote,adde,int,线段,mid,笔记,++,建图,ls 来源: https://www.cnblogs.com/zhyh/p/15030993.html