其他分享
首页 > 其他分享> > 【笔记】线段树优化建图

【笔记】线段树优化建图

作者:互联网

实际上就是利用了线段树结构将区间表示成 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