两列点均为 n n n个,分为 A A A列与 B B B列,在 A , B A,B A,B中分别有 p , q p,q p,q个关键点,其中 A A A中的 q q q个关键点的每一个,都要走到 B B B的 p p p个关键点的其中任意一个上。
在 A , B A,B A,B内部的点没有任何连边, A , B A,B A,B之间的边给出的形式如下:
A A A中的关键点可以同时移动, B B B中的任意一个关键点可以放置任意多个 A A A的关键点。求 A A A中所有关键点完成移动的最长时间。
n ≤ 1 0 5 , w ≤ 1 0 9 n\le 10^5,w\le 10^9 n≤105,w≤109
对于 n n n个点建立线段树,这样对于任意一段连续的区间的点,最多都只有 log n \log n logn个节点与之对应。线段树需要建立4个,分别表示左右两边,边的方向上行下行。
之后只要跑最短路,对所有的 A A A列的关键点的最短路径长度取 max \max max就是最后的答案。
#include
using namespace std;
typedef long long ll;
const int maxn = 2000010;
const ll inf = ~0llu >> 1u;
struct gra {
int head[maxn], to[maxn << 2], nxt[maxn << 2], cnt;
ll f[maxn << 2];
void add(int a, int b, ll c) {
nxt[++cnt] = head[a], to[head[a] = cnt] = b, f[cnt] = c;
}
};
struct dij : public gra {
struct node {
int x;
ll v;
explicit node(int x = 0, ll v = 0) : x(x), v(v) {}
bool operator<(const node &t) const {
return v > t.v;
}
};
ll dis[maxn];
int pcnt;
bool vis[maxn];
void work(int S) {
fill(dis + 1, dis + 1 + pcnt, inf);
fill(vis + 1, vis + 1 + pcnt, false);
priority_queue<node> q;
dis[S] = 0, q.push(node(S, dis[S]));
while (!q.empty()) {
int x = q.top().x;
q.pop();
if (vis[x]) continue;
vis[x] = true;
for (int i = head[x]; i; i = nxt[i]) {
int u = to[i];
if (!vis[u] && dis[u] > dis[x] + f[i]) {
dis[u] = dis[x] + f[i];
q.push(node(u, dis[u]));
}
}
}
}
} dj;
struct seg {
int pos[maxn]{}, mx;
seg() { mx = 0; }
#define mid ((l+r)>>1)
#define lch (now<<1)
#define rch (now<<1|1)
void build(int now, int l, int r) {
if (l == r) {
pos[l] = now;
mx = max(now, mx);
return;
}
build(lch, l, mid);
build(rch, mid + 1, r);
}
static void get(int now, int l, int r, int p1, int p2, vector<int> &v) {
if (l == p1 && r == p2) {
v.push_back(now);
return;
}
if (p2 <= mid) get(lch, l, mid, p1, p2, v);
else if (p1 >= mid + 1) get(rch, mid + 1, r, p1, p2, v);
else get(lch, l, mid, p1, mid, v), get(rch, mid + 1, r, mid + 1, p2, v);
}
} s;
int main() {
int n, m, p, q;
scanf("%d%d%d%d", &n, &m, &p, &q);
s.build(1, 1, n);
int cn = dj.pcnt = s.mx * 2, dn = s.mx;
for (int i = 1; i <= dn; i++) {
for (int j = 0; j <= 1; j++) {
int x = i * 2 + j;
if (x <= dn) {
dj.add(x, i, 0);
dj.add(dn + i, dn + x, 0);
dj.add(cn + x, cn + i, 0);
dj.add(cn + dn + i, cn + dn + x, 0);
}
}
int x = i;
if (x * 2 + 1 > dn && x * 2 > dn) {
dj.add(dn + x, x, 0);
x += cn;
dj.add(dn + x, x, 0);
}
}
dj.pcnt *= 2;
for (int i = 1; i <= m; i++) {
int a, b, c, d, w;
vector<int> v1, v2;
scanf("%d%d%d%d%d", &a, &b, &c, &d, &w);
s.get(1, 1, n, a, b, v1);
s.get(1, 1, n, c, d, v2);
int ins = ++dj.pcnt;
for (auto x : v1) dj.add(x, ins, w);
for (auto x : v2) dj.add(ins, cn + dn + x, 0);
ins = ++dj.pcnt;
for (auto x : v1) dj.add(ins, dn + x, 0);
for (auto x : v2) dj.add(cn + x, ins, w);
}
vector<int> x, y;
for (int i = 1, a; i <= p; i++) scanf("%d", &a), x.push_back(a);
for (int i = 1, a; i <= q; i++) scanf("%d", &a), y.push_back(a);
int S = ++dj.pcnt;
for (auto t : y) dj.add(S, cn + s.pos[t], 0);
dj.work(S);
ll res = 0;
for (auto t : x) res = max(res, dj.dis[s.pos[t]]);
if(res == inf) puts("boring game");
else printf("%lld\n", res);
return 0;
}