Files
python/TangDou/AcWing/SegmentTree/CF786B.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

137 lines
3.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}