bzoj 3073
线段树优化建图,spfa
建立两颗线段树A, B
对于线段树A,每个非根节点向其父亲节点连边,边权为0
对于线段树B,每个非叶子节点向其儿子节点连边,边权为0
线段树B的叶子节点向对应的线段树A的位置连边,边权为0
每次区间连边时,[a,b]向辅助点p1连边,边权为0
辅助点p2向区间[c,d]连边,边权为0
p1 向 p2 连边边权为1;
最后跑最短路
#include <bits/stdc++.h> const int N = 5e5 + 10, M = 3e6 + N; int cnt = 1, data[N], head[M], lson[N << 3], rson[N << 3]; struct Node {int u, v, w, nxt;} G[M << 3]; int An, Bn, tot_jd; int dis[M]; bool vis[M]; int n, m, p; void Add(int u, int v, int w) { G[cnt].v = v, G[cnt].w = w, G[cnt].nxt = head[u], head[u] = cnt ++; } // 线段树内连边 void Build_tree(int l, int r, int &jd, bool flag) { jd = ++ tot_jd; if(l == r) { if(flag) data[l] = jd; return ; } int mid = (l + r) >> 1; Build_tree(l, mid, lson[jd], flag), Build_tree(mid + 1, r, rson[jd], flag); if(flag) Add(lson[jd], jd, 0), Add(rson[jd], jd, 0); else Add(jd, lson[jd], 0), Add(jd, rson[jd], 0); } // 两颗线段树的叶子节点之间连边 void Build_tow(int l, int r, int x, int y) { if(l == r) { Add(y, x, 0); return ; } int mid = (l + r) >> 1; Build_tow(l, mid, lson[x], lson[y]), Build_tow(mid + 1, r, rson[x], rson[y]); } // 区间向辅助点连边 void Build_last(int l, int r, int jd, int x, int y, int p_, bool flag) { if(x <= l && r <= y) { if(flag) Add(jd, p_, 0); else Add(p_, jd, 0); return ; } int mid = (l + r) >> 1; if(x <= mid) Build_last(l, mid, lson[jd], x, y, p_, flag); if(y > mid) Build_last(mid + 1, r, rson[jd], x, y, p_, flag); } // 区间之间连边 void Build_three(int a, int b, int c, int d) { Build_last(1, n, An, a, b, ++ tot_jd, 1); Add(tot_jd, tot_jd + 1, 1); Build_last(1, n, Bn, c, d, ++ tot_jd, 0); } void Spfa() { std:: queue <int> Q; memset(dis, 0x3f, sizeof dis); Q.push(data[p]); dis[data[p]] = 0; while(!Q.empty()) { int top_ = Q.front(); Q.pop(); vis[top_] = 0; for(int i = head[top_]; ~ i; i = G[i].nxt) { int v = G[i].v, u = G[i].u; if(dis[v] > dis[top_] + G[i].w) { dis[v] = dis[top_] + G[i].w; if(!vis[v]) {vis[v] = 1; Q.push(v);} } } } } int main() { std:: cin >> n >> m >> p; memset(head, -1, sizeof head); Build_tree(1, n, An, 1), Build_tree(1, n, Bn, 0); Build_tow(1, n, An, Bn); for(int i = 1; i <= m; i ++) { int a, b, c, d; std:: cin >> a >> b >> c >> d; Build_three(a, b, c, d), Build_three(c, d, a, b); } Spfa(); for(int i = 1; i <= n; i ++) std:: cout << dis[data[i]] << "\n"; return 0; }