优化建图
不是哥们线段树啥都掺和,就连图论也不放过啊!
线段树优化建图
首先,我们先来看一下经典的类型:
- 点 \(u\) 向区间 \([l, r]\) 内的所有点分别连一条边(无向有向随便)。
- 区间 \([l, r]\) 内的所有点都向点 \(u\) 连一条边。
- 区间 \([l, r]\) 内的所有点分别向区间 \([L, R]\) 内的所有点连边。
对于这三种操作如果暴力建图如果是毒瘤题非常的喜欢卡空间。这时候就需要线段树优化建图了。
对于线段树我们分成两颗。一颗入树,一颗出树。
入树内是父节点连向子节点(从上往下连),出树是子节点连向父节点(从下往上)。
而入树与出树的叶子结点也要相连,这些的边权都是 \(0\),显然,入树和出树的连边反过来即可。
一般搭配 01BFS 与 dijkstra 使用,还可以有树剖。
那来一道简单的题吧。
例题:Legacy
这里只有三种操作。
- 点连点(\(O(1)\)就行)
- 点连区间
- 区间连点
处理完操作,建完图后跑一遍 dij 就行了。
戳我看代码喵~
vector<pii> g[N << 3];
int tot, rt_in, rt_out, ls[N << 3], rs[N << 3];
int pos_in[N], pos_out[N];
void build_in(int &p, int l, int r) { //建权值线段树
if (!p) p = ++tot;
if (l == r) return pos_in[l] = p, void(); //映射
int mid = l + r >> 1;
build_in(ls[p], l, mid), build_in(rs[p], mid + 1, r), g[p].push_back({ls[p], 0}), g[p].push_back({rs[p], 0}); //连边
}
void build_out(int &p, int l, int r) {
if (!p) p = ++tot;
if (l == r) return pos_out[l] = p, void();
int mid = l + r >> 1;
build_out(ls[p], l, mid), build_out(rs[p], mid + 1, r), g[ls[p]].push_back({p, 0}), g[rs[p]].push_back({p, 0}); //和上面是反着的
}
void update_in(int p, int l, int r, int L, int R, int u, int w) {
if (L <= l && r <= R) return g[pos_out[u]].push_back({p, w}), void();
int mid = l + r >> 1;
if (L <= mid) update_in(ls[p], l, mid, L, R, u, w);
if (R > mid) update_in(rs[p], mid + 1, r, L, R, u, w);
}
void update_out(int p, int l, int r, int L, int R, int v, int w) {
if (L <= l && r <= R) return g[p].push_back({pos_in[v], w}), void();
int mid = l + r >> 1;
if (L <= mid) update_out(ls[p], l, mid, L, R, v, w);
if (R > mid) update_out(rs[p], mid + 1, r, L, R, v, w);
}
const int INF = 0x3f3f3f3f3f3f3f3f;
int dis[N << 3];
bool vis[N << 3];
void dijstra(int s) { //简单的 dij
for (int i = 1; i <= tot; i++) dis[i] = INF, vis[i] = 0;
priority_queue<pii, vector<pii>, greater<pii> > q;
dis[pos_in[s]] = 0, q.push({0, pos_in[s]});
while (!q.empty()) {
int u = q.top().second; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto X : g[u]) {
int v = X.first, w = X.second;
if (dis[u] + w < dis[v]) dis[v] = dis[u] + w, q.push({dis[v], v});
}
}
}
void build(int n) { //初始化
build_in(rt_in, 1, n), build_out(rt_out, 1, n);
for (int i = 1; i <= n; i++) g[pos_in[i]].push_back({pos_out[i], 0}), g[pos_out[i]].push_back({pos_in[i], 0}); //叶子结点相连
}
signed main() {
int n = re, q = re, s = re;
build(n);
while (q--) {
int op = re, v = re;
if (op == 1) {
int u = re, w = re;
g[pos_out[v]].push_back({pos_in[u], w});
}
else if (op == 2) {
int l = re, r = re, w = re;
update_in(rt_in, 1, n, l, r, v, w);
}
else {
int l = re, r = re, w = re;
update_out(rt_out, 1, n, l, r, v, w);
}
}
dijstra(s);
for (int i = 1; i <= n; i++) wr(dis[pos_in[i]] == INF ? -1 : dis[pos_in[i]]), sp;
}

浙公网安备 33010602011771号