CF786B Legacy

题目大意

一开始有 (n) 个点,有 (m) 个操作,每个操作是以下三种之一:

  • 连边 (i o j),边权为 (w);
  • 对于所有 (iin [l,r]),连边 (i o j),边权为 (w)
  • 对于所有 (jin [l,r]),连边 (i o j),边权为 (w)

所有操作进行完后问你从 (s) 到所有点的最短路。

(1le n,mle 10^5)

题解

对于操作一,直接连即可。

对于操作二,建一棵类似于线段树之类的东西,其中的每个点都代表一个区间,同时每个点向其父节点连边(因为某个区间向 (1dots n) 中的某个点连边,就相当于其所有子区间都向这个点连边)。对于线段树中的叶子节点,从它对应的原节点向其连边。将操作中的区间 ([l,r]) 拆成 线段树上的 (log n) 个区间,这些区间都向这个点连边即可。

对于操作三同理,建一棵反向的线段树即可。

建完图跑一边最短路,时间复杂度 (O(n log n log (n log n))=O(nlog^2 n))

计算一下这张图中点和边的个数:每棵线段树有 (4n) 个点,原图中有 (n) 个点,因此点数是 (9n);每棵线段树约有 (4n) 条边,线段树的叶子节点会连 (n) 个边,每次操作最多连 (log n) 条边,于是总边数是 (10n+mlog n)

代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
typedef long long ll;
template<typename T> void Read(T &x){
	x=0;int f=1,ch;
	for(ch=getchar();!isdigit(ch);ch=getchar()) f=(ch=='-'?-1:1);
	for(;isdigit(ch);ch=getchar()) x=x*10+(ch-48);
	x*=f;
}
template<typename T,typename... Args> void Read(T &x,Args&... args){
	Read(x);Read(args...);
}
const int N=1e5+5;
const ll Infll=0x3f3f3f3f3f3f3f3fLL;
int n,q,s,tot=0,num[N];
int head[N*10],cntt=0;
struct Edge{int v,nxt;ll w;}e[int(3e6+5)];
void AddEdge(int u,int v,ll w){
	e[++cntt]=Edge{v,head[u],w};head[u]=cntt;
}
struct Segtree{
	#define ls(xx) ((xx)<<1)
	#define rs(xx) ((xx)<<1|1) 
	int dir;
	struct Node{
		int l,r,v;
	}t[N<<2];
	Segtree(int dir_):dir(dir_){}
	void Build(int p,int l,int r){
		t[p].l=l,t[p].r=r,t[p].v=++tot;
		if(l==r){
			if(~dir) AddEdge(t[p].v,num[l],0);
			else AddEdge(num[l],t[p].v,0);
			return;
		}
		int mid=(l+r)>>1;
		Build(ls(p),l,mid);
		if(~dir) AddEdge(t[p].v,t[ls(p)].v,0);
		else AddEdge(t[ls(p)].v,t[p].v,0);
		Build(rs(p),mid+1,r);
		if(~dir) AddEdge(t[p].v,t[rs(p)].v,0);
		else AddEdge(t[rs(p)].v,t[p].v,0);
	}
	void Add(int p,int l,int r,int x,ll w){
		if(l<=t[p].l&&t[p].r<=r){
			if(~dir) AddEdge(num[x],t[p].v,w);
			else AddEdge(t[p].v,num[x],w);
			return;
		}
		int mid=(t[p].l+t[p].r)>>1;
		if(l<=mid) Add(ls(p),l,r,x,w);
		if(r>mid) Add(rs(p),l,r,x,w);
	}
}tr1(1),tr2(-1);
ll dis[N*10];
void Dijkstra(){
	static int hp[N*10];int len=0;
	auto Cmp=[](int i,int j){return dis[i]>dis[j];};
	memset(dis,0x3f,sizeof(ll)*(tot+2));
	hp[++len]=num[s],dis[num[s]]=0;push_heap(hp+1,hp+len+1,Cmp);
	while(len){
		pop_heap(hp+1,hp+len+1,Cmp);
		int u=hp[len--];
		for(int i=head[u];i;i=e[i].nxt){
			if(dis[e[i].v]>dis[u]+e[i].w){
				dis[e[i].v]=dis[u]+e[i].w;
				hp[++len]=e[i].v;
				push_heap(hp+1,hp+len+1,Cmp);
			}
		}
	}
}
int main(){
	Read(n,q,s);
	For(i,1,n) num[i]=++tot;
	tr1.Build(1,1,n),tr2.Build(1,1,n);
	int op,v,l,r,w;
	For(i,1,q){
		Read(op);
		if(op==1){
			Read(l,r,w);AddEdge(num[l],num[r],w);
		}else if(op==2){
			Read(v,l,r,w);
			tr1.Add(1,l,r,v,w);
		}else if(op==3){
			Read(v,l,r,w);
			tr2.Add(1,l,r,v,w);
		}
	}
	Dijkstra();
	For(i,1,n){
		if(dis[num[i]]!=Infll) printf("%lld ",dis[num[i]]);
		else printf("-1 ");
	}
	return 0;
}
Written by Alan_Zhao
原文地址:https://www.cnblogs.com/alan-zhao-2007/p/cf786b-sol.html