CF786BLegacy
Posted wzj-xhjbk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF786BLegacy相关的知识,希望对你有一定的参考价值。
题目大意:初始给定 N 个点,支持三种操作:两点之间连边;一个点与一个连续区间编号的点之间连边;一个连续区间内的点和一个点连边,求执行 N 次操作之后的单源最短路。
题解:学会了线段树优化建图。
发现若暴力进行连边,时间和空间都会被卡到 \(O(n^2)\),直接起飞。
发现连边的点的编号是连续的,结合线段树可以维护连续区间信息的思想,就产生了线段树优化建图的方法。
在初始的 N 个节点的基础上建立两棵线段树,分别表示入树和出树,其中入树的上的各个节点允许单个节点的连接;出树上的节点允许连接单个节点。对于入树中的每个节点来说,需要连一条边权为 0 的有向边到它的两个儿子,表示若有节点连向父节点,那么一定也连向了儿子节点;对于出树上的每个节点来说,需要连一条边权为 0 的有向边到它的父节点,表示若当前节点可以连向某个节点,那么其子节点也一定可以走到这个节点。
时空复杂度分析:空间为两棵线段树的空间减去一份叶子节点的大小,即:\(3 * n\),时间复杂度为 \(elog^2v\),其中 e 是边的条数,v 是节点的个数。
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct edge
int to;
LL w;
edge(int x = -1, int y = -1)
to = x, w = y;
;
struct segtree
#define ls(o) tree[o].lc
#define rs(o) tree[o].rc
struct node
int lc, rc;
;
vector<node> tree;
int tot, rootin, rootout;
segtree(int n, vector<vector<edge>> &adj)
tot = n;
tree.resize(3 * n);
buildin(rootin, 1, n, adj);
buildout(rootout, 1, n, adj);
void buildin(int &o, int l, int r, vector<vector<edge>> &adj)
if (l == r)
o = l;
return;
o = ++tot;
int mid = l + r >> 1;
buildin(ls(o), l, mid, adj);
buildin(rs(o), mid + 1, r, adj);
adj[o].emplace_back(ls(o), 0);
adj[o].emplace_back(rs(o), 0);
void buildout(int &o, int l, int r, vector<vector<edge>> &adj)
if (l == r)
o = l;
return;
o = ++tot;
int mid = l + r >> 1;
buildout(ls(o), l, mid, adj);
buildout(rs(o), mid + 1, r, adj);
adj[ls(o)].emplace_back(o, 0);
adj[rs(o)].emplace_back(o, 0);
void link(int o, int l, int r, int x, int y, int u, int w, int opt, vector<vector<edge>> &adj) // opt 2 -> in 3 -> out
if (l == x && r == y)
opt == 2 ? adj[u].emplace_back(o, w) : adj[o].emplace_back(u, w);
return;
int mid = l + r >> 1;
if (y <= mid)
link(ls(o), l, mid, x, y, u, w, opt, adj);
else if (x > mid)
link(rs(o), mid + 1, r, x, y, u, w, opt, adj);
else
link(ls(o), l, mid, x, mid, u, w, opt, adj);
link(rs(o), mid + 1, r, mid + 1, y, u, w, opt, adj);
;
int main()
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m, s;
cin >> n >> m >> s;
vector<vector<edge>> adj(3 * n);
segtree t(n, adj);
while (m--)
int opt;
cin >> opt;
if (opt == 1)
int u, v, w;
cin >> u >> v >> w;
adj[u].emplace_back(v, w);
else
int u, l, r, w;
cin >> u >> l >> r >> w;
t.link(opt == 2 ? t.rootin : t.rootout, 1, n, l, r, u, w, opt, adj);
vector<LL> d(3 * n, 1e18);
vector<bool> expand(3 * n);
priority_queue<pair<LL, int>> q;
auto dijkstra = [&]()
d[s] = 0, q.push(make_pair(0, s));
while (!q.empty())
int u = q.top().second;
q.pop();
if (expand[u] == 1)
continue;
expand[u] = 1;
for (auto e : adj[u])
int v = e.to, w = e.w;
if (d[v] > d[u] + w)
d[v] = d[u] + w;
q.push(make_pair(-d[v], v));
;
dijkstra();
for (int i = 1; i <= n; i++)
if (d[i] == 1e18)
cout << "-1" << " ";
else
cout << d[i] << " ";
return 0;
以上是关于CF786BLegacy的主要内容,如果未能解决你的问题,请参考以下文章