线段树优化建图学习

mac2022-06-30  39

线段树优化建图

在某次CYjian神犇给我推了一道树剖+线段树优化建图+2-SAT的好(毒瘤)题后,发现自己竟然还 不会线段树优化建图,于是赶紧滚去学了一波,记下笔记


作用

用来解决区间连边(l,r)的每个点向(L,R)的每个点连边的建图方法。可以优化空间和时间。

实现

以CF786B为例。

题目要求支持以下三个操作:

单个点向单个点连边,权值为v

[ l , r ] [l,r] [l,r]中的每个点向单个点连边,权值为v

单个点向 [ l , r ] [l,r] [l,r]中的每个点连边,权值为v

然后求 s s s到每个点的单源最短路

考虑开两颗线段树,一颗用来维护2操作,一颗用来维护3操作。

对于2操作,如图:

]

考虑将线段树的每个节点也看做图中的一个点,同时每个点向父亲节点连一条权值为 0 0 0的边

接着做 2 2 2操作就可以在线段树中查找,当这个区间在线段树中被某个点包含后即用该点与单个点连边

即可,可以发现,区间 l , r l,r l,r中每个点都间接通过线段树中该点连向了要求的节点。

对于3操作,如图:

]

再造一颗线段树反过来连权值为 0 0 0的边,然后在按要求在线段树中连边即可。

最后从 s s s跑一遍 S P F A SPFA SPFA( S P F A S SPFAS SPFAS是不会死的!)即可。

代码

/******************************* Author:galaxy yr LANG:C++ Created Time:2019年10月01日 星期二 19时26分26秒 *******************************/ #include<cstdio> #include<cstring> #include<queue> using namespace std; struct IO{ template<typename T> IO & operator>>(T&res) { T q=1;char ch; while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q; res=(ch^48); while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48); res*=q; return *this; } }cin; struct edge{ int to,next,w; edge(int a=0,int b=0,int c=0):to(a),next(b),w(c){} }; struct Node{ int l,r; Node(int x=0,int y=0):l(x),r(y){} }; const int maxn=1e5+10; const int maxm=3e5+10; const long long inf=9187201950435737471LL; int head[maxm],cnt,tot,rtin,rtout,s,n,m; long long dis[maxm]; edge e[maxn*20]; Node tr[maxm]; void add(int u,int v,int w) { e[++cnt]=edge(v,head[u],w); head[u]=cnt; } void buildin(int &k,int l,int r) { if(l==r) { k=l; return; } k=++tot; int mid=(l+r)>>1; buildin(tr[k].l,l,mid); buildin(tr[k].r,mid+1,r); add(k,tr[k].l,0); add(k,tr[k].r,0); } void buildout(int &k,int l,int r) { if(l==r) { k=l; return; } k=++tot; int mid=(l+r)>>1; buildout(tr[k].l,l,mid); buildout(tr[k].r,mid+1,r); add(tr[k].l,k,0); add(tr[k].r,k,0); } void update(int k,int l,int r,const int &x,const int &y, const int &u,const int &w,const int type) { if(l>=x && r<=y) { type==2?add(u,k,w):add(k,u,w); return; } if(l>y || r<x)return; int mid=(l+r)>>1; update(tr[k].l,l,mid,x,y,u,w,type); update(tr[k].r,mid+1,r,x,y,u,w,type); } void SPFA(int s) { memset(dis,0x7f,sizeof dis); dis[s]=0; queue<int>que; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=head[u];i;i=e[i].next) if(dis[e[i].to]>dis[u]+e[i].w) dis[e[i].to]=dis[u]+e[i].w,que.push(e[i].to); } } int main() { //freopen("786B.in","r",stdin); //freopen("786B.out","w",stdout); cin>>n>>m>>s; tot=n; buildin(rtin,1,n); buildout(rtout,1,n); while(m--) { int opt,u,v,w,x,y; cin>>opt; if(opt==1) { cin>>u>>v>>w; add(u,v,w); } else { cin>>u>>x>>y>>w; update(opt==2?rtin:rtout,1,n,x,y,u,w,opt); } } SPFA(s); for(int i=1;i<=n;i++) printf("%lld ",dis[i]==inf?-1:dis[i]); putchar('\n'); return 0; }
最新回复(0)