You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
3.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int N = 100100 << 3, M = N << 2;
typedef pair<LL, int> PII;
//最短路径
LL d[N]; //最短距离数组
bool st[N];
//邻接表
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
struct Node {
int l, r;
int ls, rs; //左儿子编号,右儿子编号
} tr[N];
int rtin, rtout, cnt; //出树根编号,入树根编号,编号计数器(从n+1开始前面n个留给真实节点)
// l:左边界, r:右边界, 返回新创建的节点编号
int build1(int l, int r) {
if (l == r) {
tr[l] = {l, r}; // tr[l]:叶子节点比较牛B不用计数器生成节点号而是真实的[1~n]。这样才能真正实现最底层的重复利用,防止重复建设
return l;
}
int u = ++cnt; //非叶子节点利用cnt获取节点号
tr[u] = {l, r}; //记录区间范围
int mid = (l + r) >> 1;
tr[u].ls = build1(l, mid); //构建左子树
tr[u].rs = build1(mid + 1, r); //构建右子树
//父节点向左右儿子连权值为0的边
add(u, tr[u].ls, 0), add(u, tr[u].rs, 0);
//返回新创建的节点编号
return u;
}
int build2(int l, int r) {
if (l == r) {
tr[l] = {l, r};
return l;
}
int u = ++cnt;
tr[u] = {l, r};
int mid = (l + r) >> 1;
tr[u].ls = build2(l, mid);
tr[u].rs = build2(mid + 1, r);
//左右儿子向父节点连权值为0的边
add(tr[u].ls, u, 0), add(tr[u].rs, u, 0);
return u;
}
/**
* @brief 点向区间连边 或 区间向点连边
*
* @param u 线段树根节点u
* @param x 需要连边的点
* @param l 区间左边界
* @param r 区间右边界
* @param w 权值
*/
void add1(int u, int x, int l, int r, int w) {
if (l <= tr[u].l && tr[u].r <= r) {
add(x, u, w);
return;
}
if (l <= tr[tr[u].ls].r) add1(tr[u].ls, x, l, r, w);
if (r >= tr[tr[u].rs].l) add1(tr[u].rs, x, l, r, w);
}
void add2(int u, int x, int l, int r, int w) {
if (l <= tr[u].l && tr[u].r <= r) {
add(u, x, w);
return;
}
if (l <= tr[tr[u].ls].r) add2(tr[u].ls, x, l, r, w);
if (r >= tr[tr[u].rs].l) add2(tr[u].rs, x, l, r, w);
}
void dijkstra(int s) {
memset(d, 0x3f, sizeof(d));
d[s] = 0;
priority_queue<PII, vector<PII>, greater<PII>> q;
q.push({0, s});
while (q.size()) {
int u = q.top().second;
q.pop();
if (st[u]) continue;
st[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (d[j] > d[u] + w[i]) {
d[j] = d[u] + w[i];
q.push({d[j], j});
}
}
}
}
int main() {
//加快读入
ios::sync_with_stdio(false), cin.tie(0);
memset(h, -1, sizeof h);
int n, q, s;
cin >> n >> q >> s;
cnt = n; //可用的合法编号从n+1开始
rtin = build1(1, n); //构建入树
rtout = build2(1, n); //构建出树
int op, x, y, l, r, w;
for (int i = 1; i <= q; i++) {
cin >> op;
if (op == 1) { //点x到点y有一条边权w的边
cin >> x >> y >> w;
add(x, y, w);
} else if (op == 2) { //点x到区间[l,r]有一条边权w的边
cin >> x >> l >> r >> w;
add1(rtin, x, l, r, w);
} else if (op == 3) { //区间[l,r]到点x有一条边权w的边
cin >> x >> l >> r >> w;
add2(rtout, x, l, r, w);
}
}
//最短路径
dijkstra(s);
//输出最短路
for (int i = 1; i <= n; i++)
printf("%lld ", d[i] == INF ? -1 : d[i]);
putchar('\n');
return 0;
}