最近学了线段树优化建图,用来处理一个点向一个区间连边,但是边数太大,直接对区间中所有点连边的话会爆炸,不管是什么存图方式都存不下来,而线段树就可以用来优化这种类型的建图。
其实也不是真的建一颗线段树,只是使用了线段树将区间划分为节点的思想去使用它。
具体来说,如果是求最短路一类的问题,可以在父亲节点向左右子树连一条边权为0的边,叶子节点向他代表的端点连一条边权为0的边,然后单点向区间连边的话,就是类似线段树的区间更新,跑到一个符合的节点处就连一条边。
如果是二分图匹配类问题,那么就是父亲节点向左右子树连一条边权 + o o +oo +oo的边,叶子节点向实际端点连一条边权为1的边,区间连边与上面一致。
对于这道题来说,每次建的是有向图,那么就建两颗线段树,一个是父亲向儿子连边,一个是儿子向父亲连边。
为什么要建两颗线段树呢,如果只建一颗的话,最短路就只会是零,因为他会通过线段树上的0边权边直接走到终点
就比如下面这张图:
如果比如现在有五个点,线段树的首节点从6开始编号,采用动态开点,我们只建一颗线段树,那么每条边都是双向的,从节点2到节点1的最短路是不是永远都是0,但显然这样是不对的,所以我们需要建两颗线段树来做。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
struct Edge{
int v,w,next;
}edge[maxn<<1];
int head[maxn],top;
void init(){
top=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w){
edge[top].v=v;
edge[top].w=w;
edge[top].next=head[u];
head[u]=top++;
}
struct Tree{
int lc,rc;
}zheng[maxn<<1],fan[maxn<<1];
int tot;
//f1正向边;
int build(int l,int r,bool f){