[luogu P6348] [PA2011]Journeys
[luogu P6348] [PA2011]Journeys
题解
最直接的做法就是直接连边然后跑01最短路
但是边数特别多,所以要线段树优化建边
要注意的一点是双向边必须建两对点来辅助
不能直接只建一对点,不然会出现自己到自己的情况
code:
#include<bits/stdc++.h>
#define N 8000005
using namespace std;
struct edge {
int v, nxt, c;
} e[N << 1];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void add(int u, int v, int c) {// printf("%d ---> %d %d\n", u, v, c);
e[eid].v = v;
e[eid].c = c;
e[eid].nxt = p[u];
p[u] = eid ++;
}
int ch[N << 1][2], id[N], vis[N], n, m, cap, dis[N], tot;
void build(int &rt, int &rtt, int l, int r) {
rtt = rt = ++ tot;
if(l != r) rtt = ++ tot;
if(l == r) {
id[l] = rt;
return;
}
int mid = (l + r) >> 1;
build(ch[rt][0], ch[rtt][0], l, mid),
build(ch[rt][1], ch[rtt][1], mid + 1, r);
add(rt, ch[rt][0], 0), add(rt, ch[rt][1], 0),
add(ch[rtt][0], rtt, 0), add(ch[rtt][1], rtt, 0);
}
void insert(int rt, int l, int r, int L, int R, int x, int o) {
if(!rt) return;
if(L <= l && r <= R) {
if(o == 1) add(x, rt, 0);
else add(rt, x, 0);
return;
}
int mid = (l + r) >> 1;
if(L <= mid) insert(ch[rt][0], l, mid, L, R, x, o);
if(R > mid) insert(ch[rt][1], mid + 1, r, L, R, x, o);
}
queue<int> q0, q1;
void bfs() {
memset(dis, 0x3f, sizeof dis);
dis[id[cap]] = 0; vis[id[cap]] = 1;
q0.push(id[cap]);
while(q0.size() || q1.size()) {
int u = 0;
if(q0.size()) u = q0.front(), q0.pop();
else u = q1.front(), q1.pop();
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v, c = e[i].c;
if(dis[u] + c < dis[v]) {
dis[v] = dis[u] + c;
if(!vis[v]) {
vis[v] = 1;
if(c) q1.push(v);
else q0.push(v);
}
}
}
}
}
int main() {
init();
scanf("%d%d%d", &n, &m, &cap);
int rt1 = 0, rt2 = 0;
build(rt1, rt2, 1, n);
for(int i = 1; i <= m; i ++) {
int l, r, ll, rr;
scanf("%d%d%d%d", &l, &r, &ll, &rr);
int fr = ++ tot, to = ++ tot;
add(fr, to, 1);
insert(rt2, 1, n, l, r, fr, 0);
insert(rt1, 1, n, ll, rr, to, 1);
fr = ++ tot, to = ++ tot;//一定要写
add(fr, to, 1);
insert(rt2, 1, n, ll, rr, fr, 0);
insert(rt1, 1, n, l, r, to, 1);
}
bfs();
for(int i = 1; i <= n; i ++) printf("%d\n", dis[id[i]]);
return 0;
}