#线段树优化建图,Dijkstra#CF786B Legacy

时间:2021-03-31 19:28:52   收藏:0   阅读:27

题目

\(n\)个点的有向图,除了普通有向边\((x,y,w)\)
还有点\(x\)向区间\([l,r]\)或区间\([l‘,r‘]\)向点\(x‘\)连边,
问从点1到所有点的距离


分析

考虑最短路径,但是直接建边边数在\(O(nm)\)级别内,
考虑建两棵线段树,一棵下行边权为0,一棵上行边权为0,
对于\((x,y,w)\)直接连边即可,
对于点\(x\)连向\([l,r]\),将区间拆成\(O(logn)\)个线段树节点,
并将点\(x\)连向下行的\([l,r]\)线段树中,
同理,上行的\([l‘,r‘]\)连向点\(x‘\)中,这样边数为\(O(mlogn)\)
加上Dijkstra的时间复杂度为\(O(mlog^2n)\)


代码

#include <cstdio>
#include <cctype>
#include <algorithm> 
#define rr register
using namespace std;
const int N=300011; typedef long long lll;
struct node{int y,w,next;}e[N<<3]; pair<lll,int>heap[N];
int Cnt,n,m,S,as[N],et=1,cnt,ls[N],rs[N],root; lll dis[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(lll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void add(int x,int y,int w){e[++et]=(node){y,w,as[x]},as[x]=et;}
inline void Push(pair<lll,int>w){
	heap[++Cnt]=w;
	rr int x=Cnt;
	while (x>1){
		if (heap[x]<heap[x>>1])
		    swap(heap[x],heap[x>>1]),x>>=1;
		else return; 
	}
}
inline void Pop(){
	heap[1]=heap[Cnt--];
	rr int x=1;
	while ((x<<1)<=Cnt){
		rr int y=x<<1;
		if (y<Cnt&&heap[y+1]<heap[y]) ++y;
		if (heap[x]>heap[y]) swap(heap[x],heap[y]),x=y;
		    else return;
	}
}
inline void Dijkstra(int S){
	heap[++Cnt]=make_pair(0,S);
	for (rr int i=1;i<=cnt;++i) dis[i]=1e15; dis[S]=0;
	while (Cnt){
		rr lll t=heap[1].first; rr int x=heap[1].second;
		Pop(); if (t!=dis[x]) continue;
		for (rr int i=as[x];i;i=e[i].next)
		if (dis[e[i].y]>dis[x]+e[i].w){
			dis[e[i].y]=dis[x]+e[i].w;
			Push(make_pair(dis[e[i].y],e[i].y));
		}
	}
}
inline void build(int &k,int l,int r){
	if (l==r) {k=l; return;}
	if (!k) k=++cnt,++cnt;
	rr int mid=(l+r)>>1;
	build(ls[k],l,mid);
	build(rs[k],mid+1,r);
    add(k,ls[k],0),add(k,rs[k],0);
	if (l==mid) add(ls[k],k^1,0);
	    else add(ls[k]^1,k^1,0);
	if (mid+1==r) add(rs[k],k^1,0);
	    else add(rs[k]^1,k^1,0);
}
inline void update(int k,int l,int r,int x,int y,int z,int w){
	if (l==r){
		if (w<0) add(l,z,-w);
		    else add(z,l,w);
		return;
	}
	if (l==x&&r==y){
		if (w<0) add(k^1,z,-w);
		    else add(z,k,w);
	    return;
	}
	rr int mid=(l+r)>>1;
	if (y<=mid) update(ls[k],l,mid,x,y,z,w);
	else if (x>mid) update(rs[k],mid+1,r,x,y,z,w);
	    else update(ls[k],l,mid,x,mid,z,w),update(rs[k],mid+1,r,mid+1,y,z,w);
}
signed main(){
	n=iut(),m=iut(),S=iut(),cnt=n;
	if (!(cnt&1)) ++cnt;
	build(root,1,n);
	for (rr int i=1;i<=m;++i)
	switch (iut()){
		case 1:{
			rr int x=iut(),y=iut(),w=iut();
			add(x,y,w);
			break;
		}
		case 2:{
			rr int x=iut(),l=iut(),r=iut(),w=iut();
			if (l==r) add(x,l,w);
			    else update(root,1,n,l,r,x,w);
			break;
		}
		case 3:{
			rr int x=iut(),l=iut(),r=iut(),w=iut();
			if (l==r) add(l,x,w);
			    else update(root,1,n,l,r,x,-w);
			break;
		}
	} 
	Dijkstra(S);
	for (rr int i=1;i<=n;++i){
		if (dis[i]==1e15) putchar(‘-‘),putchar(49);
			else print(dis[i]);
		putchar(i==n?10:32);
	}
	return 0;
}

原文:https://www.cnblogs.com/Spare-No-Effort/p/14602319.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!