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

 

posted @ 2018-07-02 10:58  qmey  阅读(168)  评论(0编辑  收藏  举报