Description
小白非常喜欢玩 “县际争霸” 这款游戏,虽然他的技术并不容乐观。“县际争霸” 的地图共有两个县,每个县里各有 n n n 个据点。同一个县之间的据点是互不连通的,两个县之间的据点也是互不连通的。小白的 p p p 个战斗单位在第一个县的第 x 1 , x 2 , ⋯ , x p x_1,x_2,⋯,x_p x1,x2,⋯,xp 个据点中,而对手的 q q q 个建筑单位在第二个县第 y 1 , y 2 , ⋯ , y q y_1,y_2,⋯,y_q y1,y2,⋯,yq 个据点中。
为了发起进攻,小白建造了很多的 “折跃棱镜”。折跃棱镜可以帮助小白的单位在两个县之间移动,而且可以有多个单位同时通过折跃棱镜。具体地说,一个折跃棱镜包含有 5 个参数信息 a , b , c , d , w , a,b,c,d,w, a,b,c,d,w,代表位于第一个县任意第 x x x ( a ≤ x ≤ b ) (a\leq x \leq b) (a≤x≤b) 个据点的战斗单位可以花费 w 单位时间到达第二个县的任意第 $$y ( c ≤ y ≤ d ) (c \leq y \leq d) (c≤y≤d)个据点。折跃棱镜的通道是双向的,所以位于第二个县任意第 y y y ( c ≤ y ≤ d ) (c≤y≤d) (c≤y≤d) 个据点的战斗单位也可以花费 w w w 单位时间到达第一个县的任意第 x ( a ≤ x ≤ b ) x (a≤x≤b) x(a≤x≤b) 个据点。
如果一个小白的战斗单位到达了一个有敌方建筑单位的据点,那么这个战斗单位就会即刻投入战斗。当小白所有的战斗单位都投入了战斗之后,对手会感觉到压力太大而主动投降。小白想尽快结束这场战斗,请聪明的你帮他算一算,如果采用最优的调度策略,对手最早将在什么时刻投降(假设当前局面是零时刻)。如果存在战斗单位始终无法投入战斗,则请输出boring game。
Input
输入共
m
+
3
m+3
m+3 行,第一行输入四个正整数
n
,
m
,
p
,
q
(
1
≤
n
,
m
,
p
,
q
≤
1
0
5
)
n,m,p,q (1≤n,m,p,q≤10^5)
n,m,p,q(1≤n,m,p,q≤105)由空格间隔开,分别表示每个县的据点数量、折跃棱镜数量、小白的战斗单位数量和对手的建筑单位数量。
接下来的 m m m 行中,第 i i i 行输入五个正整数 a i , b i , c i , d i , w i ( 1 ≤ a i ≤ b i ≤ n , 1 ≤ c i ≤ d i ≤ n , 1 ≤ w i ≤ 1 0 9 ) ai,bi,ci,di,wi (1≤a_i≤b_i≤n,1≤c_i≤d_i≤n,1≤w_i≤10^9) ai,bi,ci,di,wi(1≤ai≤bi≤n,1≤ci≤di≤n,1≤wi≤109) 由空格间隔开,表示第 i 个折跃棱镜的参数,具体含义见题目描述。
接下来一行输入 p 个正整数 x 1 , x 2 , ⋯ , x p ( 1 ≤ x i ≤ n ) x_1,x_2,⋯,x_p (1≤x_i≤n) x1,x2,⋯,xp(1≤xi≤n) 由空格间隔开,分别表示小白的战斗单位所在的据点位置。
最后一行输入 q 个正整数 y 1 , y 2 , ⋯ , y q ( 1 ≤ y i ≤ n ) y_1,y_2,⋯,y_q (1≤y_i≤n) y1,y2,⋯,yq(1≤yi≤n) 由空格间隔开,分别表示对手的建筑单位所在的据点。
Output
如果对手最终会主动投降,则请输出一个非负整数,表示在小白的最优调度策略下对手最早的投降时间;如果存在战斗单位始终无法投入战斗,则请输出boring game。
Example
input
5 3 2 2
2 4 1 3 1
1 1 4 5 3
1 2 3 4 2
2 3
4 5
output
4
Note
样例中,一种最优调度策略是:第一个战斗单位从第一县的 2 号据点折跃到第二县的 4 号据点即可投入战斗,这将花费 2 单位时间,同时第二个战斗单位从第一县的 3 号据点折跃到第二县的 3 号据点再折跃到第一县的 2 号据点最后折跃到第二县的 4 号据点也可投入战斗,这将花费 4 单位时间。
Solution
暴力建边不行,看到区间我们自然可以想到用线段树来优化建图。
线段树优化建图模板题:Codeforces 786B
两边各建两颗入树(自顶向下)和出树(自下而上),再把终点一起压入队列,跑多源最短路后,取所有起点的dis最大值即可
Hint
有一说一,数组范围有点难控制…
Code
#include <bits/stdc++.h>
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef long long ll;
const ll LINF = 2e18;
const int maxn = 4e6 + 7;
int n,m,p,q,cnt;
int ecnt,head[maxn];
struct Edge{
int v,w,next;
}e[maxn<<1];
void add(int u,int v,int w){
e[++ecnt].v = v,e[ecnt].w = w,e[ecnt].next = head[u], head[u] = ecnt;
}
int in1[maxn],out1[maxn];
int in2[maxn],out2[maxn];
int to[100007];
void build1(int rt,int l,int r){
if(l == r){
in1[rt] = out1[rt] = l;return ;
}
int mid = (l + r) >> 1; in1[rt] = ++cnt; out1[rt] = ++cnt;
build1(ls,l,mid); build1(rs,mid+1,r);
add(in1[rt],in1[ls],0); add(in1[rt],in1[rs],0);
add(out1[ls],out1[rt],0); add(out1[rs],out1[rt],0);
}
void inUpdate1(int rt,int L,int R,int l,int r,int u,int w){
if(L <= l && r <= R){
add(u,in1[rt],w); return ;
}
int mid = (l + r) >> 1;
if(L <= mid) inUpdate1(ls,L,R,l,mid,u,w);
if(R > mid) inUpdate1(rs,L,R,mid+1,r,u,w);
}
void outUpdate1(int rt,int L,int R,int l,int r,int u,int w){
if(L <= l && r <= R){
add(out1[rt],u,w); return ;
}
int mid = (l + r) >> 1;
if(L <= mid) outUpdate1(ls,L,R,l,mid,u,w);
if(R > mid) outUpdate1(rs,L,R,mid+1,r,u,w);
}
void build2(int rt,int l,int r){
if(l == r){
in2[rt] = out2[rt] = ++cnt;
to[l] = cnt;
return ;
}
int mid = (l + r) >> 1; in2[rt] = ++cnt; out2[rt] = ++cnt;
build2(ls,l,mid); build2(rs,mid+1,r);
add(in2[rt],in2[ls],0); add(in2[rt],in2[rs],0);
add(out2[ls],out2[rt],0); add(out2[rs],out2[rt],0);
}
void inUpdate2(int rt,int L,int R,int l,int r,int u,int w){
if(L <= l && r <= R){
add(u,in2[rt],w); return ;
}
int mid = (l + r) >> 1;
if(L <= mid) inUpdate2(ls,L,R,l,mid,u,w);
if(R > mid) inUpdate2(rs,L,R,mid+1,r,u,w);
}
void outUpdate2(int rt,int L,int R,int l,int r,int u,int w){
if(L <= l && r <= R){
add(out2[rt],u,w); return ;
}
int mid = (l + r) >> 1;
if(L <= mid) outUpdate2(ls,L,R,l,mid,u,w);
if(R > mid) outUpdate2(rs,L,R,mid+1,r,u,w);
}
ll dis[maxn];bool vis[maxn];
struct node{
int now;
ll w;
inline bool operator<(const node&it) const{
return w > it.w;
}
};
int s[maxn],t[maxn];
inline ll Max(ll x1,ll x2){
if(x1 > x2) return x1;
return x2;
}
ll dijkstra(){
priority_queue<node>que;
for(int i = 1;i <= cnt;++i){
dis[i] = LINF,vis[i] = false;
}
for(int i = 1;i <= q;++i){
dis[to[t[i]]] = 0;que.push((node){to[t[i]], 1ll * 0});
}
while(!que.empty()){
node x = que.top();que.pop();
int u = x.now;if(vis[u]) continue;vis[u] = true;
for(int i = head[u];i;i = e[i].next){
int v = e[i].v, w = e[i].w;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;que.push((node){v,dis[v]});
}
}
}
ll res = 0;
for(int i = 1;i <= p;++i){
res = Max(res,dis[s[i]]);
}
return res;
}
int main(){
scanf("%d%d%d%d",&n,&m,&p,&q);
cnt = n;build1(1,1,n);build2(1,1,n);
for(int i = 1;i <= m;++i){
int a,b,c,d,w;scanf("%d%d%d%d%d",&a,&b,&c,&d,&w);
int u1 = ++cnt, v1 = ++cnt, u2 = ++cnt, v2 = ++cnt;
outUpdate1(1,a,b,1,n,u1,0);add(u1,v1,w);inUpdate2(1,c,d,1,n,v1,0);
outUpdate2(1,c,d,1,n,v2,0);add(v2,u2,w);inUpdate1(1,a,b,1,n,u2,0);
}
for(int i = 1;i <= p;++i) scanf("%d",&s[i]);
for(int i = 1;i <= q;++i) scanf("%d",&t[i]);
ll res = dijkstra();
if(res == LINF) printf("boring game\n"); else printf("%lld\n", res);
return 0;
}