codeforces786B Legacy 线段树优化建图

网址:https://codeforces.com/problemset/problem/786/B

题意:

给出$n$个城市和三种路径:$u$向$v$连一条带权无向边;$[l,r]$向$v$连一条带权无向边;$u$向$[l,r]$连一条带权无向边,给出一个起点$s$,求它到其他点的最短路径,如果不能到达,输出$-1$。

题解:

现在有三种操作:点对点连边,点对线段连边,线段对点连边。且点数多达$1e5$,所以就要建立线段树优化建图。建立入度树(就是边的终点)时,需要连上父节点往子节点的点且边权为$0$,建立出度树时,需要子节点往父节点连上边权为$0$的边。然后这里点对点,区间对点,点对区间连边,所以可以直接连边不需要超级结点,如果出现了区间对区间,就需要超级结点。然后连边之后在这个图上用一次$dijkstra$算法就行了。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5e5 + 5;
struct node
{
	int l, r;
};
node tr[MAXN];
struct edge
{
	int to;
	ll w;
	edge() {}
	edge(int _to, ll _w) :to(_to), w(_w) {}
	bool operator<(const edge& a)const
	{
		return w > a.w;
	}
};
vector<edge>G[MAXN];
int cnt = 0;
void buildout(int& rt, int l, int r)
{
	if (l == r)
	{
		rt = l;
		return;
	}
	rt = ++cnt;
	int m = (l + r) >> 1;
	buildout(tr[rt].l, l, m);
	buildout(tr[rt].r, m + 1, r);
	G[rt].push_back(edge(tr[rt].l, 0));
	G[rt].push_back(edge(tr[rt].r, 0));
}
void buildin(int& rt, int l, int r)
{
	if (l == r)
	{
		rt = l;
		return;
	}
	rt = ++cnt;
	int m = (l + r) >> 1;
	buildin(tr[rt].l, l, m);
	buildin(tr[rt].r, m + 1, r);
	G[tr[rt].l].push_back(edge(rt, 0));
	G[tr[rt].r].push_back(edge(rt, 0));
}
void update(int rt, int l, int r, int ql, int qr, int v, int w, int type)
{
	if (l <= ql && r >= qr)
	{
		type == 2 ? G[v].push_back(edge(rt, w)) : G[rt].push_back(edge(v, w));
		return;
	}
	int m = (ql + qr) >> 1;
	if (l <= m)
		update(tr[rt].l, l, r, ql, m, v, w, type);
	if (r > m)
		update(tr[rt].r, l, r, m + 1, qr, v, w, type);
}
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll dis[MAXN];
bool vis[MAXN];
priority_queue<edge>Q;
void dijkstra(int s)
{
	memset(vis, 0, sizeof(vis));
	memset(dis, 0x3f, sizeof(dis));
	dis[s] = 0;
	Q.push(edge(s, dis[s]));
	while (Q.size())
	{
		auto u = Q.top();
		Q.pop();
		if (vis[u.to])
			continue;
		vis[u.to] = 1;
		for (auto i : G[u.to])
		{
			int v = i.to;
			if (!vis[v] && dis[v] > dis[u.to] + i.w)
			{
				dis[v] = dis[u.to] + i.w;
				Q.push(edge(v, dis[v]));
			}
		}
	}
}
int rt1, rt2;
int main()
{
	int n, m, s;
	scanf("%d%d%d", &n, &m, &s);
	cnt = n + 1;
	buildin(rt2, 1, n);//区间出去
	buildout(rt1, 1, n);//区间进来
	int op, u, v, l, r, w;
	while (m--)
	{
		scanf("%d", &op);
		if (op == 1)
		{
			scanf("%d%d%d", &u, &v, &w);
			G[u].push_back(edge(v, w));
		}
		else
		{
			scanf("%d%d%d%d", &v, &l, &r, &w);
			update(op == 2 ? rt1 : rt2, l, r, 1, n, v, w, op);
		}
	}
	dijkstra(s);
	for (int i = 1; i <= n; ++i)
		printf("%lld%c", dis[i] >= INF ? -1 : dis[i], i == n ? '\n' : ' ');
	return 0;
}

 

posted @ 2020-02-17 23:27  Aya_Uchida  阅读(107)  评论(0编辑  收藏  举报