#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define fz(i, a, b) for (int i = a; i <= b; i++)
#define foreach(it, v) for (auto it = v.begin(); it != v.end(); it++)
// 读取输入的函数
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
const int D = 5e5; // 偏移量,用于区分两棵线段树
int n, m, st, dist[1000005], leaf[100005];
vector<pii> g[1000005]; // 邻接表存储图
// 线段树节点结构
struct node {
int l, r;
} s[100005 << 2];
// 构建线段树
inline void build(int k, int l, int r) {
s[k].l = l;
s[k].r = r;
if (l == r) {
// 叶子节点:记录原始节点对应的线段树节点编号
leaf[l] = k;
return;
}
int mid = (l + r) >> 1;
// 构建出树(从上往下):父节点向子节点连边,边权为0
g[k].push_back(pii(k << 1, 0));
g[k].push_back(pii(k << 1 | 1, 0));
// 构建入树(从下往上):子节点向父节点连边,边权为0
// 注意:入树的节点编号需要加上偏移量D
g[(k << 1) + D].push_back(pii(k + D, 0));
g[(k << 1 | 1) + D].push_back(pii(k + D, 0));
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
}
// 连接函数:处理区间连边
inline void connect(int k, int l, int r, int v, int w, int tp) {
// 当前节点区间完全包含在目标区间内
if (l <= s[k].l && s[k].r <= r) {
if (tp) {
// tp=1:操作3,从区间[l,r]到点v
// 入树区间节点 -> 出树叶子节点
g[k + D].push_back(pii(v, w));
} else {
// tp=0:操作2,从点v到区间[l,r]
// 出树叶子节点 -> 入树区间节点
g[v].push_back(pii(k, w));
}
return;
}
int mid = (s[k].l + s[k].r) >> 1;
// 递归处理子区间
if (r <= mid) {
connect(k << 1, l, r, v, w, tp);
} else if (l > mid) {
connect(k << 1 | 1, l, r, v, w, tp);
} else {
connect(k << 1, l, mid, v, w, tp);
connect(k << 1 | 1, mid + 1, r, v, w, tp);
}
}
signed main() {
n = read();
m = read();
st = read();
// 构建线段树
build(1, 1, n);
// 处理m个操作
fz(i, 1, m) {
int opt = read();
if (opt == 1) {
// 操作1:点v到点u,边权w
int v = read(), u = read(), w = read();
g[leaf[v]].push_back(pii(leaf[u], w));
} else {
// 操作2或3:点v与区间[l,r]之间的连边
int v = read(), l = read(), r = read(), w = read();
// opt%2: 操作2返回0,操作3返回1
connect(1, l, r, leaf[v], w, opt % 2);
}
}
// 连接两棵线段树的叶子节点(原始节点)
// 同一个原始节点在出树和入树中的对应节点互相连边,边权为0
fz(i, 1, n) {
g[leaf[i]].push_back(pii(leaf[i] + D, 0));
g[leaf[i] + D].push_back(pii(leaf[i], 0));
}
// Dijkstra求最短路
priority_queue<pii, vector<pii>, greater<pii>> q;
// 初始化距离数组
memset(dist, 0x3f, sizeof(dist));
dist[leaf[st] + D] = 0; // 从起点对应的入树叶子节点开始
q.push(pii(0, leaf[st] + D));
while (!q.empty()) {
pii p = q.top();
q.pop();
int x = p.second, sum = p.first;
// 如果当前距离不是最短距离,跳过
if (dist[x] < sum) continue;
// 遍历所有邻接边
foreach(it, g[x]) {
int y = it->first, z = it->second;
if (dist[y] > sum + z) {
dist[y] = sum + z;
q.push(pii(dist[y], y));
}
}
}
// 输出结果
fz(i, 1, n) {
if (dist[leaf[i]] == 0x3f3f3f3f3f3f3f3fll) {
printf("-1 ");
} else {
printf("%lld ", dist[leaf[i]]);
}
}
return 0;
}
CF786B Legacy
最新推荐文章于 2025-12-16 14:17:05 发布

434

被折叠的 条评论
为什么被折叠?



