CF786B Legacy 题解 线段树优化建图
题目传送门
题意
-
给定一张
n 个节点的有向正权图,起点为s ,共有q 次操作,操作分三种。-
点连点
-
点连区间
-
区间连点
-
-
求从起点出发到各个点的最短路长度,若不连通则输出
-1 。
题解
先考虑暴力连边,发现时间复杂度达到了
考虑到区间连边,那么可以对于一个区间进行拆分。
我们很容易想到线段树。
考虑将线段树的节点作为代替一个区间的虚点。
显然我们需要两棵线段树,不然跑出来距离都是
我们以左边线段树的叶子节点为实际的点。
用红线代表双向边,橙色代表向下的单向边,蓝色代表向上的单向边,紫色代表向右的单向边。
显然这是初始必须要连的边,同时这些边的边权为
初始化时间复杂度
考虑操作
直接实际的点连单向边即可。
单次操作时间复杂度
例如连
考虑操作
点连区间,我们将区间剖分成线段树上的节点,然后实际的点向各个表示区间的点连接即可。
单次操作时间复杂度
例如
考虑操作
单次操作时间复杂度
区间连点,同样我们将区间剖分为线段树上的节点,然后表示区间的点连向实际的点即可。
例如
最后合起来图就成了这样。
然后从原点对应的实点开始跑 Dijkstra 即可。
记得空间开大!记得开 long long!
空间复杂度上界
时间复杂度上界
代码
const int N=5e5+5,D=5e5,INF=1e17;
int n,m,st,dis[N<<1],node[N];
bool vst[N<<1];
vector<pair<int,int> >es[N<<1];
#define mid ((l+r)>>1)
#define xl (x<<1)
#define xr (x<<1|1)
inline void build(int x,int l,int r){
if(l==r){node[l]=x;return ;}
es[x].pb(mp(0,xl));es[x].pb(mp(0,xr));
es[xl+D].pb(mp(0,x+D));es[xr+D].pb(mp(0,x+D));
build(xl,l,mid);build(xr,mid+1,r);
}
inline void add(int x,int l,int r,int L,int R,int v,int w,int op){
if(L<=l&&r<=R){
if(op==2) es[v].pb(mp(w,x));
else es[x+D].pb(mp(w,v));
return ;
}
if(L<=mid) add(xl,l,mid,L,R,v,w,op);
if(R>mid) add(xr,mid+1,r,L,R,v,w,op);
}
inline void dijkstra(int s){
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
fill(dis,dis+(N<<1)+1,INF);dis[s]=0;q.push(mp(0,s));
while(!q.empty()){
int x=q.top().second,sum=q.top().first;
q.pop();
if(vst[x]) continue;
vst[x]=1;
for(re i=0;i<es[x].size();++i){
int t=es[x][i].second,w=es[x][i].first;
if(dis[t]>sum+w){
dis[t]=sum+w;
q.push(mp(dis[t],t));
}
}
}
}
// ---------- Graph ---------- //
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
rd(n);rd(m);rd(st);
build(1,1,n);
for(re i=1;i<=n;++i) es[node[i]].pb(mp(0,node[i]+D)),es[node[i]+D].pb(mp(0,node[i]));
for(re i=1;i<=m;++i){
int op,u,v,w,l,r;
rd(op);
if(op==1){
rd(v);rd(u);rd(w);
es[node[v]].pb(mp(w,node[u]));
}
else{
rd(v);rd(l);rd(r);rd(w);
add(1,1,n,l,r,node[v],w,op);
}
}
dijkstra(node[st]);
for(re i=1;i<=n;++i){
if(dis[node[i]]==INF) cout<<"-1 ";
else wr(dis[node[i]]),putchar(' ');
}puts("");
return 0;
}
// ---------- Main ---------- //