CF786B Legacy 线段树优化建图

洛谷题目链接

题意

首先想到单源最短路,但是如果暴力模拟就会导致从区间里每一个点连向另一个点时最坏情况时间复杂度达到O(N*N),显然会TLE。那么看到区间操作,自然会想到处理区间操作的数据结构,这一题就是一道线段树题。

想法

【线段树优化建图】

1.由于直接暴力模拟连边导致TLE,我们可以按照题意建两颗线段树TreeIn(外部一点连向一个区间)和TreeOut(一个区间连向一个点),线段树中的线段编号(编号异于已知点编号)用vector存图,利用线段树特性,减少连边次数。线段树内部的区间使用选取正确的方向建立边权为0的单向边)。

2.线段树的更新操作并不操作线段树本身,只是在vector数组中建立一条和相关线段树区间相连接的边。

3.使用dijstra找最短路。

#include 
#include 
#include 
#include 

using namespace std;

const int MAXN = 100100;

const long long int INF  = 0x3f3f3f3f3f3f3f3f;

struct _Edge
{
	long long int to;
	long long int cost;
};

//边要开够 
vector<_Edge> Edge[MAXN*10];

long long int n,q,s;
long long int Count;

long long int TreeIn[MAXN<<2],TreeOut[MAXN<<2];

struct _dist
{
	long long int pos;
	long long int dis;
};

inline void AddEdge(long long int u,long long int v,long long int cost)
{
	_Edge New;
	New.to = v;
	New.cost = cost;
	Edge[u].push_back(New);
}

void BuildTree(long long int Index,long long int l,long long int r)
{
	if(l == r)
	{
		TreeIn[Index] = l;
		TreeOut[Index] = l;
		return;
	}
	
	long long int Mid = (l+r)>>1;
	
	BuildTree(Index*2,l,Mid);
	BuildTree(Index*2+1,Mid+1,r);
	
	//为某个区块编号 
	TreeIn[Index] = ++Count;
	TreeOut[Index] = ++Count;
	
	AddEdge(TreeIn[Index],TreeIn[Index*2],0);
	AddEdge(TreeIn[Index],TreeIn[Index*2+1],0);
	AddEdge(TreeOut[Index*2],TreeOut[Index],0);
	AddEdge(TreeOut[Index*2+1],TreeOut[Index],0);
}

void UpdateIn(long long int Index,long long int l,long long int r,long long int L,long long int R,long long int num,long long int cost)
{
	if(l <= L && r >= R)
	{
		AddEdge(num,TreeIn[Index],cost);
		return;
	}
	
	long long int Mid = (L+R)>>1;
	
	if(l <= Mid)
	{
		UpdateIn(Index*2,l,r,L,Mid,num,cost);
	}
	if(r > Mid)
	{
		UpdateIn(Index*2+1,l,r,Mid+1,R,num,cost);
	}
}

void UpdateOut(long long int Index,long long int l,long long int r,long long int L,long long int R,long long int num,long long int cost)
{
	if(l <= L && r >= R)
	{
		AddEdge(TreeOut[Index],num,cost);
		return;
	}
	
	long long int Mid = (L+R)>>1;
	
	if(l <= Mid)
	{
		UpdateOut(Index*2,l,r,L,Mid,num,cost);
	}
	if(r > Mid)
	{
		UpdateOut(Index*2+1,l,r,Mid+1,R,num,cost);
	}
}

bool operator>(_dist a,_dist b)
{
	return a.dis > b.dis;
}

priority_queue<_dist,vector<_dist>,greater<_dist> > Dist;
long long int DisResult[MAXN*10];

void Dij(void)
{
	memset(DisResult,0X3F,sizeof(DisResult));
	DisResult[s] = 0;
	
	_dist Tmp;
	Tmp.pos = s;
	Tmp.dis = 0;
	
	Dist.push(Tmp);
	
	while(!Dist.empty())
	{
		_dist Index = Dist.top();
		Dist.pop();
		
		if(DisResult[Index.pos] != Index.dis)
		{
			continue;
		}
		
		for(int i = 0;i < Edge[Index.pos].size();i++)
		{
			
			if(DisResult[Edge[Index.pos][i].to] > Edge[Index.pos][i].cost+DisResult[Index.pos])
			{
				DisResult[Edge[Index.pos][i].to] = Edge[Index.pos][i].cost+DisResult[Index.pos];
				_dist Tmp;
				Tmp.pos = Edge[Index.pos][i].to;
				Tmp.dis = DisResult[Edge[Index.pos][i].to];
				Dist.push(Tmp);
			}
		}
	}
}


int main(void)
{
	cin >> n >> q >> s;
	
	Count = n;
	BuildTree(1,1,n);
	for(int i = 1;i <= q;i++)
	{
		long long int type;
		cin >> type;
		if(type == 1)
		{
			long long int u,v,w;
			cin >> u >> v >> w;
			AddEdge(u,v,w);
		}
		else if(type == 2)
		{
			long long int v,l,r,w;
			cin >> v >> l >> r >> w;
			UpdateIn(1,l,r,1,n,v,w);
		}
		else if(type == 3)
		{
			long long int v,l,r,w;
			cin >> v >> l >> r >> w;
			UpdateOut(1,l,r,1,n,v,w);
		}
	}
	
	Dij();
	
	for(int i = 1;i <= n;i++)
	{
		if(DisResult[i] == INF)
		{
			cout << -1 << ' ';
			continue;
		}
		cout << DisResult[i] << ' ';
	}
	cout << endl;
	return 0;
}

 

你可能感兴趣的:(算法,数据结构,NOIP)